Trie(2)洛谷题目

题单:https://www.luogu.com.cn/training/9372

P3879 [TJOI2010]阅读理解

题型:字符串检索

空间卡的很紧,普通的trie会MLE

const int maxn=5e5+100;
bool st[maxn][1010];
int nex[maxn][26],cnt=0;
void insert(string s,int l,int x){ // 插入字符串
    int p=0;
    for(int i=0;i<l;i++){
        int c=s[i]-'a';
        if(!nex[p][c]) nex[p][c]=++cnt;// 如果没有,就添加结点
        p=nex[p][c];
    }
    st[p][x]=1;
}
int find(string s,int l){// 查找字符串
    int p=0;
    for(int i=0;i<l;i++){
        int c=s[i]-'a';
        if(!nex[p][c]) return 0;
        p=nex[p][c];
    }
    return p;
}

int main(){
    int n=read;
    rep(q,1,n){
        int k=read;
        rep(i,1,k){
            string s;cin>>s;
            insert(s,s.size(),q);
        }
    }
    int m=read;
    while(m--){
        string s;cin>>s;
        if(int t=find(s,s.size())){
            rep(i,1,n)
                if(st[t][i]) cout<<i<<" ";
        }
        puts("");
    }
    
    
    
    return 0;
}
View Code

用bitset优化掉标记数组的空间

const int maxn=5e5+100;
bitset<1001> st[500007];
int nex[maxn][26],cnt=0;
void insert(string s,int l,int x){ // 插入字符串
    int p=0;
    for(int i=0;i<l;i++){
        int c=s[i]-'a';
        if(!nex[p][c]) nex[p][c]=++cnt;// 如果没有,就添加结点
        p=nex[p][c];
    }
    st[p][x]=1;
}
int find(string s,int l){// 查找字符串
    int p=0;
    for(int i=0;i<l;i++){
        int c=s[i]-'a';
        if(!nex[p][c]) return 0;
        p=nex[p][c];
    }
    return p;
}

int main(){
    int n=read;
    rep(q,1,n){
        int k=read;
        rep(i,1,k){
            string s;cin>>s;
            insert(s,s.size(),q);
        }
    }
    int m=read;
    while(m--){
        string s;cin>>s;
        if(int t=find(s,s.size())){
            rep(i,1,n)
                if(st[t][i]) cout<<i<<" ";
        }
        puts("");
    }
    
    
    
    return 0;
}
View Code

P2922 [USACO08DEC]Secret Message G

题型:多询问多前缀统计

注意加上前缀相同并且长度比他长的个数,减掉字符串相等的个数,因为重复计算了。

const int maxn=5e5+100;
int sum[maxn],now[maxn];
int nex[maxn][26],cnt=0;
int s[maxn];

int find(int s[],int x){
    int p=0,res=0;
    rep(i,0,x-1){
        int c=s[i];
        if(!nex[p][c]) return res;
        p=nex[p][c];
        res+=now[p];
    }
    return res-now[p]+sum[p];
}

int main(){
    int m=read,n=read;
    while(m--){
        int x=read;
        int p=0;
        for(int i=0;i<x;i++){
            int c=read;
            if(!nex[p][c]) nex[p][c]=++cnt;// 如果没有,就添加结点
            p=nex[p][c];
            sum[p]++;
        }
        now[p]++;
    }
    while(n--){
        int x=read;
        rep(i,0,x-1) s[i]=read;
        cout<<find(s,x)<<endl;
    }
    
    
    return 0;
}
View Code

P4551 最长异或路径

前置知识 https://www.acwing.com/problem/content/145/

const int maxn=1e6+100;

vector<PII>g[maxn];
int dis[maxn];
void dfs(int u,int fa){
    for(int i=0;i<g[u].size();i++){
        int j=g[u][i].first,w=g[u][i].second;
        if(j==fa) continue;
        dis[j]=dis[u]^w;
        dfs(j,u);
    }
}
int nex[maxn][2],idx;

void insert(int x){
    int p=0;
    for(int i=31;i>=0;i--){
        int &s=nex[p][x>>i&1];
        if(!s) s=++idx;
        p=s;
    }
}

int search(int x)
{
    int p = 0, res = 0;
    for (int i = 31; i >= 0; i -- )
    {
        int s = x >> i & 1;
        if (nex[p][!s])
        {
            res += 1 << i;
            p = nex[p][!s];
        }
        else p = nex[p][s];
    }
    return res;
}



int main(){
    
    int n=read;
    rep(i,1,n-1){
        int u=read,v=read,w=read;
        g[u].push_back({v,w});
        g[v].push_back({u,w});
    }
    dfs(1,-1);
    for(int i=1;i<=n;i++) insert(dis[i]);
    int res = 0;
    for (int i = 1; i <= n; i ++ ) 
        res = max(res, search(dis[i]));
    cout<<res<<endl;
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/OvOq/p/15029108.html