• BZOJ 3881: [Coci2015]Divljak


    Description

    有两个集合(ST),(S)集合已知。
    有两个操作
    添加一个字符串到(T)
    询问T中有多少(S_i)

    (n,qleqslant 10^5,len(|S|),len(|T|)leqslant 2 imes 10^5)

    Solution

    Trie树+DFS序.

    添加一个字符串就要把Trie树上经过的节点及其fail树上的祖先+1
    将他差分一下,每次询问出现次数就变成了询问子树和。
    然后就是几条树梿的+1操作,因为差分过了,所以每个节点+1,相邻LCA-1

    Code

    /**************************************************************
        Problem: 3881
        User: BeiYu
        Language: C++
        Result: Accepted
        Time:16216 ms
        Memory:514652 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
     
    const int N = 2000050;
    const int M = 26;
     
    namespace Bit {
        int d[N],n;
         
        void init(int x) { n=x; }
        void Add(int x,int v) { for(;x<=n;x+=x&-x) d[x]+=v; }
        int Qur(int x,int r=0) { for(;x;x-=x&-x) r+=d[x];return r; }
    }
     
    namespace Tree {
        vector<int> g[N];
        int cnt;
        int b[N],f[N][M],d[N],t1[N],t2[N];
         
        void AddEdge(int u,int v) { g[u].push_back(v),g[v].push_back(u); }
        void DFS(int rt) {
            stack<int> stk;
            stk.push(rt),f[rt][0]=rt,d[rt]=1;
            for(int x;!stk.empty();) {
                x=stk.top();
                if(b[x]) { t2[x]=cnt,stk.pop();continue; }
                b[x]=1,t1[x]=++cnt;
                for(int i=0,v;i<(int)g[x].size();i++) 
                    if((v=g[x][i])!=f[x][0]) f[v][0]=x,d[v]=d[x]+1,stk.push(v);
            }
        }
        void init() {
            for(int j=1;j<M;j++) for(int i=1;i<=cnt;i++)
                f[i][j]=f[f[i][j-1]][j-1];
        }
        int LCA(int u,int v) {
            if(d[u]<d[v]) swap(u,v);
            int l=d[u]-d[v];
            if(l) for(int i=M-1;~i;i--) if(l&(1<<i)) u=f[u][i];
            if(u==v) return u;
            for(int i=M-1;~i;--i) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
            return f[u][0];
        }
    };
     
     
    namespace AC {
        int cnt,rt;
        int f[N],ch[N][M],ed[N];
         
        void init() { rt=cnt=0; }
        void insert(char* s,int id) {
            int l=strlen(s),x=rt;
            for(int i=0;i<l;i++) {
                int v=s[i]-'a';
                if(!ch[x][v]) ch[x][v]=++cnt;
                x=ch[x][v];
            }ed[id]=x;
        }
        void Build() {
            queue<int> q;
            f[rt]=rt;
            for(int i=0;i<M;i++) if(ch[rt][i]) q.push(ch[rt][i]),f[ch[rt][i]]=rt;
            for(int x;!q.empty();) {
                x=q.front(),q.pop();
                for(int i=0;i<M;i++) {
                    if(!ch[x][i]) { ch[x][i]=ch[f[x]][i];continue; }
                    int v=ch[x][i];
                    f[v]=ch[f[x]][i],q.push(v);
                }
            }
        }
        void get_f() {
            for(int i=1;i<=cnt;i++) Tree::AddEdge(i,f[i]);
            Tree::DFS(0);
            Tree::init();
             
    //      for(int i=1;i<=cnt;i++) cout<<i<<" "<<f[i]<<endl;
    //      for(int i=1;i<=cnt;i++) cout<<Tree::d[i]<<" ";cout<<endl;
    //      for(int i=1;i<=cnt;i++) cout<<Tree::t1[i]<<" ";cout<<endl;
    //      for(int i=1;i<=cnt;i++) cout<<Tree::t2[i]<<" ";cout<<endl;
        }
    };
     
    int cmp(int x,int y) { return Tree::t1[x]<Tree::t1[y]; }
    vector<int> a;
    void add_str(char* s) {
        int l=strlen(s),x=AC::rt;
        a.clear();
        for(int i=0;i<l;i++) {
            int v=s[i]-'a';
            x=AC::ch[x][v];
            a.push_back(x);
        }
        sort(a.begin(),a.end(),cmp);
        x=a.size();
    //  for(int i=0;i<x;i++) cout<<a[i]<<" ";cout<<endl;
        Bit::Add(Tree::t1[a[0]],1);
        for(int i=1;i<x;i++) {
            Bit::Add(Tree::t1[Tree::LCA(a[i],a[i-1])],-1);
            Bit::Add(Tree::t1[a[i]],1);
        }
    }
     
    int n,q;
    char s[N];
     
    int main() {
    //  freopen("in.in","r",stdin);
        scanf("%d",&n);
        AC::init();
        for(int i=1;i<=n;i++) {
            scanf("%s",s);
            AC::insert(s,i);
        }
        AC::Build();
        AC::get_f();
        Bit::init(AC::cnt+1);
    //  int oo,ooo;
    //  while(cin>>oo>>ooo) cout<<Tree::LCA(oo,ooo)<<endl;
        scanf("%d",&q);
        for(int opt,x;q--;) {
            scanf("%d",&opt);
            if(opt==1) {
                scanf("%s",s);
                add_str(s);
            } else {
                scanf("%d",&x);
                printf("%d
    ",Bit::Qur(Tree::t2[AC::ed[x]])-Bit::Qur(Tree::t1[AC::ed[x]]-1));
            }
        }return 0;
    }
    

      

  • 相关阅读:
    LeetCode 102. 二叉树的层次遍历
    Java | JDK8下的ConcurrentHashMap#get
    Java | JDK8下的ConcurrentHashMap#putValue
    CCF | 小中大
    Jvm | 《深入理解Java虚拟机》读书笔记 |
    Jvm | 《深入理解Java虚拟机》读书笔记 | 线程安全与锁优化
    3. 帧定格和导出单帧
    2. premiere 项目管理
    1.后期特效合成AE概述&&工作流程&&磁盘缓存清理
    贷款减值准备和折现回拨
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6721217.html
Copyright © 2020-2023  润新知