• 【经典】虚树+字典树——ICPC NCNA 2018 A


    首先建立好trie,由于问题询问的结点和不超过2e5,可以用虚树解决

    bug百出。。调试了一上午

    /*
    对给定串建立trie,标记上终止结点,d[u]表示结点u的深度 
    对于每个询问,标记k个串对应的终止结点,然后建立虚树
    虚树里维护size[u],fa[u],所有size[u]=L的点都是符合要求的点,其贡献为
        -d[fa[u]]+d[u]; 
    */
    
    #include<bits/stdc++.h>
    using namespace std;
    #define N 400005
    
    int n,Q,K,L;
    int id[N];//第i个串对应的终止结点 
    
    int d[N],f[N][25],dfn[N],vis[N];//trie树上结点深度,倍增数组
    struct trie{
        int nxt[N][26],root,L;
        int newnode(){
            ++L;
            memset(nxt[L],-1,sizeof nxt[L]);
            return L;
        }
        void init(){
            L=0;
            root=newnode();
        }
        void insert(char buf[],int idd){
            int len=strlen(buf);
            int now=root;
            for(int i=0;i<len;i++){
                if(nxt[now][buf[i]-'a']==-1)
                    nxt[now][buf[i]-'a']=newnode();
                now=nxt[now][buf[i]-'a'];
            }
            id[idd]=now;
        }
        void build(){
            stack<int>q;
            q.push(root);
            d[root]=0;
            int idx=0;
            while(q.size()){
                int now=q.top();q.pop();
                dfn[now]=++idx;
                for(int i=0;i<26;i++)
                    if(nxt[now][i]!=-1){
                        q.push(nxt[now][i]);
                        d[nxt[now][i]]=d[now]+1;
                        f[nxt[now][i]][0]=now;
                    }
            }
            f[1][0]=1;
            for(int i=1;i<=20;i++)
                for(int j=1;j<=L;j++)
                    f[j][i]=f[f[j][i-1]][i-1];
        } 
    }tr;
    
    int cmp(int a,int b){
        return dfn[id[a]]<dfn[id[b]];
    }
    int LCA(int u,int v){
        if(d[u]<d[v])swap(u,v);
        int dif=d[u]-d[v];
        for(int i=20;i>=0;i--)
            if((dif>>i) & 1)u=f[u][i];
        if(u==v)return u;
        for(int i=20;i>=0;i--)
            if(f[u][i]!=f[v][i])
                u=f[u][i],v=f[v][i];
        return f[u][0]; 
    }
    
    vector<int>G[N];
    inline void add(int u,int v){G[u].push_back(v);}
    int size[N],stk[N],top,ans;//虚树 
    void insert(int x){
        if(x==1)return;
        int t=LCA(x,stk[top]);
        if(t!=stk[top]){
            while(top>1 && dfn[stk[top-1]]>dfn[t]){
                add(stk[top-1],stk[top]);
                top--;
            }
            if(dfn[t]>dfn[stk[top-1]]){
                G[t].clear();
                add(t,stk[top]);
                stk[top]=t;
            }else {
                add(t,stk[top]);
                top--;
            }
        }
        G[x].clear();
        stk[++top]=x;
    } 
    void dfs(int u,int pre){//在虚树中dfs 
        //cout<<u<<" ";
        size[u]=vis[u];
        for(auto v:G[u])if(v!=pre){
            dfs(v,u);
            size[u]+=size[v];
        }
        if(size[u]==L)
            ans+=d[u]-d[pre];
    }
    
    char buf[N];
    int a[N];
    int main(){
        //freopen("3.in","r",stdin);
        //freopen("3.out","w",stdout);
        cin>>n>>Q;
        tr.init();
        for(int i=1;i<=n;i++){//插入第i个字符串 
            scanf("%s",buf);
            tr.insert(buf,i);
        }
        tr.build();
    
        
        while(Q--){
            scanf("%d%d",&K,&L);
            for(int i=1;i<=K;i++)scanf("%d",&a[i]);
            sort(a+1,a+1+K,cmp);
            for(int i=1;i<=K;i++)vis[id[a[i]]]=1;//标记终止结点 
            
            G[1].clear();
            top=0;stk[++top]=1;
            for(int i=1;i<=K;i++)
                insert(id[a[i]]);//建立虚树 
            for(int i=1;i<top;i++)
                add(stk[i],stk[i+1]);
            /*for(int i=1;i<=tr.L;i++){
                cout<<i<<" ";
                for(auto v:G[i])cout<<v<<" ";
                puts("");
            }*/
            ans=0;
            dfs(1,1);
            cout<<ans<<'
    ';
            
            for(int i=1;i<=K;i++)vis[id[a[i]]]=0;
        }
    }
  • 相关阅读:
    html
    头部标签
    ajax
    分辨率
    js 运动基础
    js DOM
    js定时器
    js数组
    js基础
    例子:js简易日历
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12813281.html
Copyright © 2020-2023  润新知