• bzoj4231: 回忆树


    一道好题。

    考虑拆分询问,对于经过LCA的出现位置,可以把前链和后链接近LCA部分的slen-1个字符直接取出进行KMP计算,复杂度O(sigema S)

    那么现在就要计算树上一条上至下的链形成的串中,询问串出现了多少次(前链是下至上的,把询问串反过来即可)

    考虑把这样的询问拆分成两条根到点的链,离线询问,将询问串建成AC自动机。

    最后遍历整棵树同时AC自动机识别,搜到对应位置+1,回溯-1,保证记录的是根到链这个串被AC机识别的情况

    当树上遍历到询问结束点,AC机上对应询问串结束点fail树的权值和即为答案,用树状数组维护即可

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    using namespace std;
    const int _=1e2;
    const int maxn=1e5+_;
    const int maxs=3e5+_;
    
    namespace T
    {
        struct node
        {
            int x,y,c,next;
        }a[2*maxn];int len,last[maxn];
        void ins(int x,int y,int c)
        {
            len++;
            a[len].x=x;a[len].y=y;a[len].c=c;
            a[len].next=last[x];last[x]=len;
        }
        int f[30][maxn],dep[maxn];
        int LCA(int x,int y)
        {
            if(dep[x]<dep[y])swap(x,y);
            for(int i=25;i>=0;i--)
                if(dep[x]-dep[y]>=(1<<i))x=f[i][x];
            if(x==y)return x;
            for(int i=25;i>=0;i--)
                if(dep[x]>=(1<<i)&&f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
            return f[0][x];
        }
        int findkfa(int x,int k)
        {
            for(int i=25;i>=0;i--)
                if(k>=(1<<i))x=f[i][x],k-=(1<<i);
            return x;
        }
        int c[maxn];
        void dfs(int x)
        {
            for(int i=1;(1<<i)<=dep[x];i++)f[i][x]=f[i-1][f[i-1][x]];
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(y!=f[0][x])
                {
                    f[0][y]=x;
                    dep[y]=dep[x]+1;
                    c[y]=a[k].c;
                    dfs(y);
                }
            }
        }
        vector<int>vec[maxn];int pos[2*maxn];
        void hang(int x,int z,int slen,int id)
        {
            if(dep[x]-dep[z]<slen)return ;
            int tx=findkfa(x,dep[x]-dep[z]-(slen-1));
            vec[tx].push_back(-id);
            vec[x].push_back(id);
        }
    }using namespace T;
    
    char ss[maxs];int slen,as[maxn];
    namespace S1
    {
        int sa[2*maxn],alen,p[2*maxn];
        int main(int x,int y,int z)
        {
            if(dep[x]+dep[y]-2*dep[z]<slen)return 0;
            alen=0;
            int tx=findkfa(x,max(0,dep[x]-dep[z]-(slen-1)));
            while(tx!=z)sa[++alen]=c[tx],tx=f[0][tx];
            int tip=alen;
            int ty=findkfa(y,max(0,dep[y]-dep[z]-(slen-1)));
            while(ty!=z)sa[++alen]=c[ty],ty=f[0][ty];
            reverse(sa+tip+1,sa+alen+1);
            
            p[1]=0; int j=0;
            for(int i=2;i<=slen;i++)
            {
                while(j!=0&&ss[i]!=ss[j+1])j=p[j];
                if(ss[i]==ss[j+1])j++;
                p[i]=j;
            }
            j=0; int ret=0;
            for(int i=1;i<=alen;i++)
            {
                while(j!=0&&sa[i]!=ss[j+1]-'a'+1)j=p[j];
                if(sa[i]==ss[j+1]-'a'+1)j++;
                if(j==slen)ret++;
            }
            return ret;
        }
    }
    namespace S2
    {
        namespace A
        {
            struct node
            {
                int w[30],fail;
            }tr[2*maxs];int trlen;
            void insert(int id)
            {
                int now=0;
                for(int i=1;i<=slen;i++)
                {
                    int x=ss[i]-'a'+1;
                    if(tr[now].w[x]==0)tr[now].w[x]=++trlen;
                    now=tr[now].w[x];
                }
                T::pos[id]=now;
            }
            int head,tail,list[2*maxs];
            void bfs()
            {
                head=1,tail=2,list[1]=0;
                while(head!=tail)
                {
                    int now=list[head]; head++;
                    for(int x=1;x<=26;x++)
                    {
                        int son=tr[now].w[x]; if(son==0)continue;
                        if(now==0)tr[son].fail=0;
                        else
                        {
                            int pre=tr[now].fail;
                            while(pre!=0&&tr[pre].w[x]==0)pre=tr[pre].fail;
                            tr[son].fail=tr[pre].w[x];
                        }
                        list[tail++]=son;
                    }
                }
            }
        }using namespace A;
        namespace F
        {
            struct node
            {
                int x,y,next;
            }a[4*maxs];int len,last[2*maxs];
            void ins(int x,int y)
            {
                len++;
                a[len].x=x;a[len].y=y;
                a[len].next=last[x];last[x]=len;
            }
            int z,L[2*maxs],R[2*maxs];
            void dfs(int x)
            {
                L[x]=++z;
                for(int k=last[x];k;k=a[k].next)
                    dfs(a[k].y);
                R[x]=z;
            }
            int s[2*maxs];
            int lowbit(int x){return x&-x;}
            void change(int x,int k){while(x<=trlen+10)s[x]+=k,x+=lowbit(x);}
            int getsum(int x){int ret=0;while(x>0)ret+=s[x],x-=lowbit(x);return ret;}
            void update(int x)
            {
                for(int i=0;i<T::vec[x].size();i++)
                {
                    int p=vec[x][i],op=1;
                    if(p<0)op=-1,p=-p;
                    as[p/2]+=op*(getsum(R[pos[p]])-getsum(L[pos[p]]-1));
                }
            }
        }
        void dfs(int now,int x)
        {
            F::change(F::L[now],1);
            F::update(x);
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(y!=T::f[0][x])
                {
                    int tt=now;
                    while(tt!=0&&tr[tt].w[T::c[y]]==0)tt=tr[tt].fail;
                    dfs(tr[tt].w[T::c[y]],y);
                }
            }
            F::change(F::L[now],-1);
        }
        void main()
        {
            bfs();
            for(int i=1;i<=trlen;i++)F::ins(tr[i].fail,i);
            F::dfs(0);
            dfs(0,1);
        }
    }
    
    int main()
    {
        int n,Q,x,y; char sc[3];
        scanf("%d%d",&n,&Q);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%s",&x,&y,sc+1);
            ins(x,y,sc[1]-'a'+1),ins(y,x,sc[1]-'a'+1);
        }
        T::dfs(1);
        
        for(int i=1;i<=Q;i++)
        {
            scanf("%d%d%s",&x,&y,ss+1); slen=strlen(ss+1);
            int z=T::LCA(x,y);
            if(y==z)swap(x,y),reverse(ss+1,ss+slen+1);
            if(x==z)
                T::hang(y,x,slen,i*2),S2::insert(i*2);
            else
            {
                as[i]+=S1::main(x,y,z);
                T::hang(y,z,slen,i*2),S2::insert(i*2);
                reverse(ss+1,ss+slen+1);
                T::hang(x,z,slen,i*2+1),S2::insert(i*2+1);
            }
        }
        S2::main();
        
        for(int i=1;i<=Q;i++)printf("%d
    ",as[i]);
        
        return 0;
    }
  • 相关阅读:
    cmd 新建安卓工程
    新创建的android工程里面没有activity问题解决
    背景色横向渐变css5
    Serialable与Parcelable
    Observer观察者模式
    Linux基础(1)
    android 出现Make sure the Cursor is initialized correctly before accessing data from it
    android项目中导入actionbarsherlock 需要注意的地方
    android BadgeView的使用(图片上的文字提醒)
    android仿系统Launcher界面,实现分屏,左右滑动效果(ViewSwitcher)
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/11294066.html
Copyright © 2020-2023  润新知