• BZOJ4545: DQS的trie 广义后缀自动机 + LCT


    特别鸣神犇 fcwww 替我调出了无数个错误(没他的话我都快自闭了),祝大佬省选rp++ 

    板子题,给我写了一天QAQ......

    用 LCT 维护后缀树,暴力更新用 LCT 区间更新链即可

    其实,在计算本职不同子串的时候很多网友算的都有点麻烦

    不管实在后缀自动机,还是广义后缀自动机中,动态更新本质不同子串数量用最后新加的点更新即可,和其他点是无关的.

    Code:

    #include <queue> 
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <vector> 
    #define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout) 
    #define maxn 800000 
    #define N 10 
    #define ll long long 
    using namespace std; 
    char str[maxn]; 
    long long cur_ans; 
    struct Link_Cut_Tree{
        int ch[maxn][2],f[maxn],tag[maxn],sta[maxn],val[maxn];
        int get(int x) {return ch[f[x]][1]==x; }
        int which(int x){ return ch[f[x]][1]==x;}
        int isRoot(int x){ return !(ch[f[x]][1]==x||ch[f[x]][0]==x);}
        int lson(int x){ return ch[x][0];}
        int rson(int x){return ch[x][1];}
        void add(int x,int delta){if(!x)return;val[x]+=delta,tag[x]+=delta;}
        void pushdown(int x){if(tag[x]) add(lson(x),tag[x]),add(rson(x),tag[x]),tag[x]=0;}
        void rotate(int x){
            int old=f[x],fold=f[old],which=get(x);
            if(!isRoot(old)) ch[fold][ch[fold][1]==old]=x;
            ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
            ch[x][which^1]=old,f[old]=x,f[x]=fold;
        }
        void splay(int x){
            int v=0,u=x;
            sta[++v]=u;
            while(!isRoot(u)) sta[++v]=f[u],u=f[u];
            while(v) pushdown(sta[v--]);
            u=f[u];
            for(int fa;(fa=f[x])!=u && x;rotate(x))
                if(f[fa]!=u) rotate(get(fa)==get(x)?fa:x);
        }
        void Access(int x){
            for(int y=0;x;y=x,x=f[x])
                splay(x),ch[x][1]=y;
        }
        void link(int a,int b){
            Access(a),splay(a),add(a,val[b]),f[b]=a;
        }
        void cut(int b){
            Access(b),splay(b);
            add(lson(b),-val[b]),f[lson(b)]=ch[b][0]=0;
        }
    }tree; 
    struct SAM{
        int ch[maxn][10],f[maxn],dis[maxn];
        int tot,last;             
        void init(){ last=tot=1; } 
        int ins(int c){
            int p=last,np=++tot; last=np; dis[np]=dis[p]+1;tree.val[np]=tree.tag[np]=1;
            while(p&&!ch[p][c])ch[p][c]=np,p=f[p];
            if(!p) f[np]=1,tree.link(1,np);
            else{
                int q=ch[p][c],nq;
                if(dis[q]==dis[p]+1)f[np]=q,tree.link(q,np);
                else{
                    nq=++tot;
                    dis[nq]=dis[p]+1;
                    memcpy(ch[nq],ch[q],sizeof(ch[q])); 
                    f[nq]=f[q];
                    tree.link(f[q],nq),tree.cut(q),tree.link(nq,q),tree.link(nq,np);
                    f[q]=f[np]=nq;
                    while(p&&ch[p][c]==q) ch[p][c]=nq,p=f[p];
                }
            }
            cur_ans+=dis[np] - dis[f[np]]; 
            return np; 
        }
    }sam; 
    struct Node{
        int u,c; 
        Node(int u=0,int c=0):u(u),c(c){} 
    };               
    queue<int>Q; 
    vector<int>mark; 
    vector<Node>G[maxn]; 
    int idx[maxn]; 
    void DFS(int u,int fa){
        int k=G[u].size();
        for(int i=0;i<k;++i){      
            Node j=G[u][i];
            if(j.u==fa) continue;        
            sam.last=idx[u],idx[j.u]=sam.ins(j.c);
            DFS(j.u,u);  
        }
        G[u].clear(); 
    }
    void build_Tree(int n,int st){       
        for(int i=1;i<n;++i) {     
            int u,v;     
            char c[10];       
            scanf("%d%d",&u,&v);
            scanf("%s",c);        
            G[u].push_back(Node(v,c[0]-'a')); 
            G[v].push_back(Node(u,c[0]-'a'));        
        }       
        DFS(st,0);     
    }
    int main(){
        //setIO("input");            
        int lll,n,m;  
        scanf("%d",&lll);
        
        sam.init(),idx[1] = 1;             
    
        scanf("%d",&n);     
        build_Tree(n,1); 
    
        scanf("%d",&m); 
    
        for(int i=1;i<=m;++i) {
            int opt_idx,a,b; 
            scanf("%d",&opt_idx); 
            if(opt_idx==1)  printf("%lld
    ",cur_ans);  
            if(opt_idx==2) {
                scanf("%d%d",&a,&b);
                build_Tree(b,a);              
            }
            if(opt_idx==3) {   
                scanf("%s",str); 
                a=strlen(str); 
                b=1; 
                bool flag = 0; 
                for(int j=0;j<a;++j) { 
                    b=sam.ch[b][str[j]-'a']; 
                    if(!b)  flag = 1; 
                } 
                if(flag) printf("0
    ");  
                else {                             
                    tree.Access(b); 
                    tree.splay(b); 
                    printf("%d
    ",tree.val[b]); 
                }
            }
        }
        return 0; 
    }
    

      

  • 相关阅读:
    Python并发编程之深入理解yield from语法(八)
    Python并发编程之从生成器使用入门协程(七)
    Python并发编程之消息队列补充及如何创建线程池(六)
    Delphi中Chrome Chromium、Cef3学习笔记(一)
    Webbrowser指定IE内核版本(更改注册表)
    C#截取字符串按字节截取SubString
    C# DataGridView导出Excel
    C# Microsoft.Office不存在空间名称Interop和Excel
    c#线程间传递参数
    C#根据进程名称获取进程的句柄?
  • 原文地址:https://www.cnblogs.com/guangheli/p/10625484.html
Copyright © 2020-2023  润新知