zoukankan      html  css  js  c++  java
  • P5212-SubString【LCT,SAM】

    正题

    题目链接:https://www.luogu.com.cn/problem/P5212


    题目大意

    开始一个字符串(S),有(n)次操作

    1. (S)末尾加入一个字符串
    2. 询问一个串在(S)中出现了多少次

    强制在线


    解题思路

    强制在线的话,只有( ext{SAM})能够支持动态插字符了,但是我们平时统计答案的时候要先做一次拓扑排序然后上传信息。

    这里要动态维护( ext{parents})树的话用( ext{LCT})就好了,就是链修改加单点查询,然后因为根是指定的可以少写很多操作。

    时间复杂度(O( (n+S)log |S|))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    using namespace std;
    const int N=6e5*2+10;
    int n,cnt,len[N],fa[N],ch[N][26];
    char st[N];
    struct LCT{
        int t[N][2],lazy[N],w[N],fa[N];
        stack<int> s;
        bool Nroot(int x)
        {return fa[x]&&((t[fa[x]][0]==x)||(t[fa[x]][1]==x));}
        bool Direct(int x)
        {return t[fa[x]][1]==x;}
        void Add(int x,int val)
        {if(x)w[x]+=val,lazy[x]+=val;return;}
        void PushDown(int x){
            if(!lazy[x])return;
            if(t[x][0])Add(t[x][0],lazy[x]);
            if(t[x][1])Add(t[x][1],lazy[x]);
            lazy[x]=0;return;
        }
        void Rotate(int x){
            int y=fa[x],z=fa[y];
            int xs=Direct(x),ys=Direct(y);
            int w=t[x][xs^1];
            if(Nroot(y))t[z][ys]=x;
            t[y][xs]=w;t[x][xs^1]=y;
            if(w)fa[w]=y;fa[y]=x;fa[x]=z;
            return;
        }
        void Splay(int x){
            int y=x;s.push(x);
            while(Nroot(y))y=fa[y],s.push(y);
            while(!s.empty())PushDown(s.top()),s.pop();
            while(Nroot(x)){
                y=fa[x];
                if(!Nroot(y))Rotate(x);
                else if(Direct(y)==Direct(x))
                    Rotate(y),Rotate(x);
                else Rotate(x),Rotate(x);
            }
            return;
        }
        void Access(int x){
            for(int y=0;x;y=x,x=fa[x])
                Splay(x),t[x][1]=y;
            return;
        }
        void Link(int x,int y)//x为单点,y为树
        {fa[x]=y;Access(y);Splay(y);Add(y,w[x]);return;}
        void Cut(int x)//将x切断为单点
        {Access(x);Splay(x);Add(t[x][0],-w[x]);fa[t[x][0]]=0;t[x][0]=0;return;}
    }T;
    void decode(char *s,int l,int mask) {
    	for (int j=0;j<l;j++) {
    		mask=(mask*131+j)%l;
    		swap(s[j],s[mask]);
    	}
    	return;
    }
    int insert(int c,int p){
        int np=++cnt;len[np]=len[p]+1;T.w[np]++;
        for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
        if(!p)fa[np]=1,T.Link(np,1);
        else{
            int q=ch[p][c];
            if(len[p]+1==len[q])fa[np]=q,T.Link(np,q);
            else{
                int nq=++cnt;len[nq]=len[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[nq]));
                fa[nq]=fa[q];fa[np]=fa[q]=nq;
                T.Cut(q);T.Link(nq,fa[nq]);
                T.Link(np,nq);T.Link(q,nq);
                for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
            }
        }
        return np;
    }
    int main()
    {
        scanf("%d",&n);
        scanf("%s",st);int l=strlen(st);
        int p=cnt=1;int mask=0;
        for(int i=0;i<l;i++)
            p=insert(st[i]-'A',p);
        while(n--){
            char op[5];
            scanf("%s %s",op,st);l=strlen(st);
            decode(st,l,mask);
            if(op[0]=='Q'){
                int x=1;
                for(int i=0;i<l;i++)
                    if(!ch[x][st[i]-'A'])
                    {x=0;break;}
                    else x=ch[x][st[i]-'A'];
                if(!x)puts("0");
                else{
                    T.Splay(x);
                    printf("%d
    ",T.w[x]);
                    mask^=T.w[x];
                }
            }
            else{
                for(int i=0;i<l;i++)
                    p=insert(st[i]-'A',p);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    C++中dynamic_cas操作符的工作原理
    wcf服务契约的重载
    db2学习笔记
    微软新特性下的异常处理
    任务取消TASK
    socket多文件发送(压缩,解压)
    oracle 表分区例子
    Task构造
    TASK 的使用
    Asp.Net 用户验证(自定义IPrincipal和IIdentity)
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14278978.html
Copyright © 2011-2022 走看看