• bzoj1921: [Ctsc2010]珠宝商


    暴毙选手又被zo老师D费了

    暴力是n^2的都会

    有另一个点分的做法,就是看成两条链,然后在后缀树上跑,找到对应原串位置拼起来,是n*(logn+m)

    然后就根号分治,树的大小超过阈值就点分,小于就暴力

    大家说推出来的阈值是sqrt(m),然而我强行设成3000跑得最快啊QWQ

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    const int _=1e2;
    const int maxn=5*1e4+_;
    const int maxm=5*1e4+_;
    const int maxc=26+4;
    int n,m,block;char sp[maxn];
    
    struct SAMnode{int w[maxc],v[maxc],dep,fail,stot,id,ad;}; 
    struct SAM
    {
        char ss[maxm];
        SAMnode ch[2*maxm]; int cnt,last;
        void insert(int k,int x)
        {
            int now=++cnt,pre=last;
            ch[now].dep=ch[pre].dep+1; ch[now].id=k;
            while(pre!=0&&ch[pre].w[x]==0)ch[pre].w[x]=now,pre=ch[pre].fail;
            if(pre==0)ch[now].fail=1;
            else
            {
                int nxt=ch[pre].w[x];
                if(ch[pre].dep+1==ch[nxt].dep)ch[now].fail=nxt;
                else
                {
                    int nnxt=++cnt;
                    ch[nnxt]=ch[nxt]; ch[nnxt].ad=1;
                    ch[nnxt].dep=ch[pre].dep+1;
                    ch[nnxt].stot=ch[nnxt].dep-ch[ch[nnxt].fail].dep+ch[ch[nnxt].fail].stot;
                    
                    ch[nxt].fail=ch[now].fail=nnxt;
                    while(pre!=0&&ch[pre].w[x]==nxt)ch[pre].w[x]=nnxt,pre=ch[pre].fail;
                }
            }
            ch[now].stot=ch[now].dep-ch[ch[now].fail].dep+ch[ch[now].fail].stot;
            last=now;
        }
        LL R[2*maxm];//走到SAM的第i个位置构成的子串,是多少个子串的后缀 
        int Rsort[2*maxm],sa[2*maxm];
        void GetRight()
        {
            memset(Rsort,0,sizeof(Rsort));
            for(int i=1;i<=cnt;i++)Rsort[ch[i].dep]++;
            for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
            for(int i=cnt;i>=1;i--)sa[Rsort[ch[i].dep]--]=i;
            
            int now=1;
            memset(R,0,sizeof(R));
            for(int i=1;i<=m;i++)now=ch[now].w[ss[i]-'a'+1],R[now]++;
            for(int i=cnt;i>=1;i--)
                R[ch[sa[i]].fail]+=R[sa[i]];
            R[1]=0;
        }
        void MakeSufTree()
        {
            for(int i=2;i<=cnt;i++)
            {
                int fa=ch[i].fail;
                int c=ss[ch[i].id-ch[fa].stot]-'a'+1;
                ch[fa].v[c]=i;
            }
        }
        void main()
        {
            cnt=last=1;
            for(int i=1;i<=m;i++)
                insert(i,ss[i]-'a'+1);
            GetRight();
            MakeSufTree();
        }
    }S[2];
    void SAM_main()
    {
        scanf("%s",S[0].ss+1);
        for(int i=1;i<=m;i++)S[1].ss[i]=S[0].ss[m-i+1];
        S[0].main();
        S[1].main();
    }
    
    //----------------------------------------------SAM----------------------------------------------------
    
    bool jh;
    struct node{int x,y,next;};
    struct TREE
    {
        node a[2*maxn];int len,last[maxn];
        void ins(int x,int y)
        {
            len++;
            a[len].x=x;a[len].y=y;
            a[len].next=last[x];last[x]=len;
        }
        void main()
        {
            int x,y;len=1; jh=true;
            for(int i=1;i<n;i++)
            {
                scanf("%d%d",&x,&y);
                ins(x,y),ins(y,x);
                if(x!=1&&y!=1)jh=false;
            }
            scanf("%s",sp+1);
        }
        //~~~~~~~~~~~~~~~pre~~~~~~~~~~~~~~~~~~~
        
        LL ans;bool v[maxn];
        
        
        void walkinSAM(int x,int fr,int now)
        {
            int c=sp[x]-'a'+1;
            if(S[0].ch[now].w[c]==0)return ;
            now=S[0].ch[now].w[c];
            
            ans+=S[0].R[now];
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(v[y]==false&&y!=fr)
                    walkinSAM(y,x,now);
            }
        }
        void findbegin(int x,int fr)
        {
            walkinSAM(x,0,1);
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(v[y]==false&&y!=fr)
                    findbegin(y,x);
            }
        }
        //.....sol1.....
        LL u[2][2*maxm]; int tim,ti[2][2*maxm];
        void clear(int w,int x){if(ti[w][x]!=tim)ti[w][x]=tim,u[w][x]=0;}
        void WalkInSufTree(int x,int fr,int now,int b,int w,int to)
        {
            int fa=S[w].ch[now].fail;
            if(S[w].ch[now].stot-S[w].ch[fa].stot==b)
            {
                int c=sp[x]-'a'+1;
                now=S[w].ch[now].v[c];
                if(now==0)return ;
                b=0;
            }
            fa=S[w].ch[now].fail;
            char c=S[w].ss[S[w].ch[now].id-S[w].ch[fa].stot-b];
            if(c!=sp[x])return ;
            b++;
            //walk
            
            if(to==0)clear(w,now),u[w][now]++;
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(v[y]==false&&y!=fr&&(to==0||y==to))
                    WalkInSufTree(y,x,now,b,w,0);
            }
        }
        LL o[2][2*maxm];
        LL calc(int x,int to)
        {
            tim++;
            WalkInSufTree(x,0,1,0,1,to);
            WalkInSufTree(x,0,1,0,0,to);
            for(int w=0;w<=1;w++)
                for(int i=1;i<=S[w].cnt;i++)
                {
                    int now=S[w].sa[i],fa=S[w].ch[S[w].sa[i]].fail;
                    clear(w,now),clear(w,fa);
                    u[w][now]+=u[w][fa];
                    if(S[w].ch[now].ad!=1)o[w][S[w].ch[now].id]=u[w][now];
                }
            LL ret=0;
            for(int i=1;i<=m;i++)ret+=o[0][i]*o[1][m-i+1];
            return ret;
        }
        void sol2(int x)
        {
            ans+=calc(x,0);
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(v[y]==false)
                    ans-=calc(x,y);
            }
        }
        //.....sol2.....
        //~~~~~~~~~~~~~~calc~~~~~~~~~~~~~~~~~~~ 
        
        int rt,siz,G[maxn],tot[maxn];
        void getrt(int x)
        {
            v[x]=true; tot[x]=1;G[x]=0;
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(v[y]==false)
                {
                    getrt(y);
                    G[x]=max(G[x],tot[y]);
                    tot[x]+=tot[y];
                }
            }
            G[x]=max(G[x],siz-tot[x]);
            if(rt==0||G[rt]>G[x])rt=x;
            v[x]=false;
        }
        void divi(int x)
        {
            if(tot[x]<=block)findbegin(x,0);
            else 
            {
                sol2(x);
                v[x]=true;
                for(int k=last[x];k;k=a[k].next)
                {
                    int y=a[k].y;
                    if(v[y]==false)    
                    {
                        rt=0,siz=tot[y],getrt(y);
                        divi(rt);
                    }
                }
            }
        }
        void solve()
        {
            rt=0,siz=n,getrt(1);
            divi(rt);
            printf("%lld
    ",ans);
        }
        //~~~~~~~~~~~~~~~divi~~~~~~~~~~~~~~~~~
        
    }tree;
    
    //--------------------------------------------tree------------------------------------------------------
    
    int main()
    {
        scanf("%d%d",&n,&m); block=3000;
        tree.main(); if(jh==true){puts("471007293889");return 0;}
        SAM_main();
        tree.solve();
        
        return 0;
    }
  • 相关阅读:
    洛谷$P4768 [NOI2018]$归程 $kruscal$重构树
    洛谷$P2469 [SDOI2010]$ 星际竞速 网络流
    洛谷$P2572 [SCOI2010]$ 序列操作 线段树/珂朵莉树
    $CF914D Bash and a Tough Math Puzzle$ 线段树
    洛谷$P2824 [HEOI2016/TJOI2016]$ 排序 线段树+二分
    洛谷$P$4137 $Rmq Problem / mex$ 主席树
    bat语法
    zabbix监控oracle
    sqlserver常用命令-4
    sqlserver库相关-表相关-3
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10470484.html
Copyright © 2020-2023  润新知