字典树

Trie与01Trie

总结

一个字符串是树中的一条链,从根节点叶子结点

字典树中,字符放在边上,节点仅代表编号

具体的,通常用$tr[N][c]$,表示编号为i的节点向下边为字符c连接的节点编号

Trie一般形式(插入)

1
2
3
4
5
6
int tr[N][26];
int tot=1;
for(auto c : s){
    if(tr[t][c-'a']==0) tr[t][c-'a']=++tot;
    t=tr[t][c-'a'];
}

01Trie一般形式(插入)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int tr[N*30][2];
int tot=1;
void insert(int x){
    int p = 1;
    for(int i=31;i>=0;i--){
        int u = (x>>i)&1;
        if(!tr[p][u]) tr[p][u] = ++tot;
        p = tr[p][u];
    }
}

Trie

Trie字符串统计

地址

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void SINGLE_TEST()
{
    int n;cin>>n;
    while(n--){
        char op;cin>>op;
        string s;cin>>s;
        if(op=='I'){
            int t=1;
            for(auto c : s){
                if(tr[t][c-'a']==0) tr[t][c-'a']=++tot;
                t=tr[t][c-'a'];
            }
            cnt[t]++;
        }else{
            int t=1;
            bool ok=0;
            for(auto c : s){
                if(tr[t][c-'a']==0){
                    ok=1;
                    cout<<0<<'\n';
                    break;
                }
                t=tr[t][c-'a'];
            }
            if(!ok)
                cout<<cnt[t]<<'\n';
        }
    }
}

E - Yet Another Sigma Problem

地址

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
void SINGLE_TEST()
{
    int n;cin>>n;
    ll ans=0;
    for(int i=1;i<=n;i++){
        string s;cin>>s;
        int t=1;
        for(auto c : s){
            if(tr[t][c-'a']==0) tr[t][c-'a']=++tot;
            t=tr[t][c-'a'];
            ans+=cnt[t]++;
        }
    }
    cout<<ans<<'\n';
}

01Trie

最大异或对

地址

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void insert(int x){
    int p = 1;
    for(int i=31;i>=0;i--){
        int u = (x>>i)&1;
        if(!tr[p][u]) tr[p][u] = ++tot;
        p = tr[p][u];
    }
}
int query(int x){
    int p = 1;
    int res = 0;
    for(int i=31;i>=0;i--){
        int u = (x>>i)&1;
        if(tr[p][!u]){
            res += 1<<i;
            p = tr[p][!u];
        }else{
            p = tr[p][u];
        }
    }
    return res;
}

void SINGLE_TEST()
{
    int n;cin>>n;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        insert(a[i]);
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        ans = max(ans, query(a[i]));
    }
    cout<<ans<<'\n';
}

D. Dr. Evil Underscores

地址

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int tr[N*30][2];
int dep[N*30];
int tot=1;
void insert(int x){
    int p=1;
    for(int j=30;j>=0;j--){
        int t=(x>>j&1);
        if(!tr[p][t]) tr[p][t]=++tot;
        dep[p]=j;
        p=tr[p][t];
    }
}
void SINGLE_TEST()
{
    int n;cin>>n;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        insert(a[i]);
    }
    function<int(int)> dfs=[&](int x){
        int ans=0;
        if(!tr[x][0] && !tr[x][1]) return 0LL;    
        if(tr[x][0] && tr[x][1]){
            return min(dfs(tr[x][0]),dfs(tr[x][1]))+(1LL<<dep[x]);
        }
        if(tr[x][0]){
            return dfs(tr[x][0]);
        }
        if(tr[x][1]){
            return dfs(tr[x][1]);
        }
    };
    cout<<dfs(1)<<'\n';
}

C. Xor Tree

地址

一般对于求删除数,我们可以反向考虑求保留数

参考

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void SINGLE_TEST()
{
    int n;cin>>n;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        insert(a[i]);
    }
    function<int(int)> dfs=[&](int x){
        if(!tr[x][0] && !tr[x][1]) return 1LL;
        if(!tr[x][0]) return dfs(tr[x][1]);
        if(!tr[x][1]) return dfs(tr[x][0]);
        return max(dfs(tr[x][0]),dfs(tr[x][1]))+1;
    };
    cout<<n-dfs(1)<<'\n';
}
本博客已稳定运行
使用 Hugo 构建
主题 StackJimmy 设计