• BZOJ4963 String


    Link
    先考虑离线做法:动态构建SAM,同时维护(f_l)表示以当前串末尾为右端点,左端点为(l)的答案。
    插入一个字符会改变它在parent树上祖先的(endpos)集合,考虑往(endpos)集合中插入一个元素的贡献。
    对于(xsubseteq endpos),左端点为(x-i+1)的答案要和(i)(max)
    由此增加的贡献是一个等差数列,因此可以线段树维护。
    贡献相同的区间显然越短越好,因此只要考虑插入元素和集合最大的元素一起产生的的贡献。
    那么每个节点维护(endpos)集合最大元素,因为每次更新一个点和它的所有的祖先,且更新的链上的(endpos)集合最大元素相同,用LCT维护即可。
    在线的话只需要把线段树改成主席树就可以了。

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    const int N=200007;
    int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
    int fetch(){char c=getchar();while(!islower(c))c=getchar();return c;}
    int n,cnt=1,tot,now=1,root1[N],root2[N],ch[N][2],fa[N],tag[N],len[N],link[N],trans[N][26];
    char str[N];
    struct node{int ls,rs,mx;}t[N*200];
    #define mid ((l+r)>>1)
    void update(int&p,int l,int r,int L,int R,int x)
    {
        t[++tot]=t[p],p=tot;
        if(L<=l&&r<=R) return t[p].mx=std::max(t[p].mx,x),void();
        if(L<=mid) update(t[p].ls,l,mid,L,R,x);
        if(R>mid) update(t[p].rs,mid+1,r,L,R,x);
    }
    int query(int p,int l,int r,int x){return l==r? t[p].mx:std::max(t[p].mx,x<=mid? query(t[p].ls,l,mid,x):query(t[p].rs,mid+1,r,x));}
    #undef mid
    #define lc ch[x][0]
    #define rc ch[x][1]
    int nroot(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
    void pushall(int x){if(!x)return;if(nroot(x))pushall(fa[x]);tag[lc]=tag[rc]=tag[x];}
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=ch[y][1]==x;
        if(nroot(y)) ch[z][y==ch[z][1]]=x;
        fa[x]=z,fa[y]=x,fa[ch[x][!k]]=y,ch[y][k]=ch[x][!k],ch[x][!k]=y;
    }
    void splay(int x)
    {
        pushall(x);
        for(int y;nroot(x);rotate(x)) if(nroot(y=fa[x])) rotate((ch[y][0]==x)^(ch[fa[y]][0]==y)? x:y);
    }
    void access(int x)
    {
        for(int y=0;x;x=fa[y=x])
    	if(splay(x),(rc=y)&&tag[x]&&len[x])
    	{
    	    if(tag[x]>len[x]) update(root1[n],1,100000,1,tag[x]-len[x],len[x]);
    	    if(tag[x]>=len[x]) update(root2[n],1,100000,tag[x]-len[x]+1,tag[x],tag[x]);
    	}
    }
    void cut(int x,int y){splay(x),splay(y),ch[y][1]^x? splay(x),fa[x]=0:ch[y][1]=fa[x]=0;}
    void make(int x){access(x),splay(x),tag[x]=n;}
    #undef lc
    #undef rc
    void extend(int c)
    {
        int p=now,q;len[now=++cnt]=len[p]+1;
        for(;p&&!trans[p][c];p=link[p]) trans[p][c]=now;
        if(!p) return fa[now]=link[now]=1,make(now);
        if(len[q=trans[p][c]]==len[p]+1) return fa[now]=link[now]=q,make(now);
        memcpy(trans[++cnt],trans[q],104),len[cnt]=len[p]+1,splay(q),tag[cnt]=tag[q],cut(q,link[q]),fa[cnt]=link[cnt]=link[q],fa[q]=link[q]=fa[now]=link[now]=cnt,make(now);
        for(;p&&trans[p][c]==q;p=link[p]) trans[p][c]=cnt;
    }
    int main()
    {
        scanf("%s",str+1);
        for(int i=1;str[i];++i) ++n,root1[n]=root1[n-1],root2[n]=root2[n-1],extend(str[i]-'a');
        for(int m=read(),ans=0;m;--m)
    	if(read()==1) str[0]=(fetch()-'a'+ans)%26+'a',str[++n]=str[0],root1[n]=root1[n-1],root2[n]=root2[n-1],extend(str[0]-'a');
    	else
    	{
    	    int l=(read()+ans-1)%n+1,r=(read()+ans-1)%n+1;
    	    if(l>r) std::swap(l,r);
    	    printf("%d
    ",ans=std::max(query(root1[r],1,100000,l),query(root2[r],1,100000,l)-l+1));
    	}
    }
    
  • 相关阅读:
    oracel 复制A列的内容到列
    视图转为表
    面向对象
    银弹效应
    解决linux删除文件后空间没有释放问题
    HttpAnalyzerStdV7安装教程
    HttpUploader6.2-process版本
    Chrome浏览器控件安装方法
    Firefox浏览器控件安装方法
    通达OA整合教程
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12320319.html
Copyright © 2020-2023  润新知