bzoj2555 SubString(后缀自动机+LCT)

83 篇文章 0 订阅

bzoj2555 SubString

原题地址http://www.lydsy.com/JudgeOnline/problem.php?id=2555

题意:
给你一个字符串init,要求你支持两个操作

(1):在当前字符串的后面插入一个字符串

(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)

你必须在线支持这些操作。

数据范围
字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000

题解:
动态维护right集合。
那么就是维护每个点的parent树子树大小。

一眼LCT维护子树大小。那不就跟大融合一样?
然后狂T不止,大概是无限循环了,等改了再UPD吧。
UPD:原来先断原pa,再连nB,再连原pa,无限循环,
改成先连原pa,再断原pa,再连nB,A了。不明原因。待UPD。

另外一种做法是可以不维护子树大小,于是一个点加进来时,就把它到根的这条链上的所有点的ans+=这个点的大小。
打标记在splay时pushdown即可,注意询问前要把询问的点push一次。

代码:
一、打标记

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int N=3000050;
int ccc;
struct node
{
    int fa,ch[2],w,tag;
    void init(int x) {fa=0; ch[0]=ch[1]=0; w=x;tag=0;}
}tr[N];
int q,tail=1,root=1,last=1,ch[N][26],len[N],pa[N],lens;
char str[N],opt[10];
bool isroot(int x) {return tr[tr[x].fa].ch[0]!=x&&tr[tr[x].fa].ch[1]!=x;}
void rotate(int x)
{
    int y=tr[x].fa; int z=tr[y].fa; 
    if(!isroot(y)) {if(tr[z].ch[0]==y) tr[z].ch[0]=x; else tr[z].ch[1]=x;}
    tr[x].fa=z;
    int l=(tr[y].ch[0]==x)?0:1; int r=l^1;
    tr[y].ch[l]=tr[x].ch[r]; tr[tr[x].ch[r]].fa=y;
    tr[x].ch[r]=y; tr[y].fa=x;
}
void pushdown(int x)
{
    if(tr[x].tag) 
    {
        if(tr[x].ch[0]) tr[tr[x].ch[0]].tag+=tr[x].tag,tr[tr[x].ch[0]].w+=tr[x].tag;
        if(tr[x].ch[1]) tr[tr[x].ch[1]].tag+=tr[x].tag,tr[tr[x].ch[1]].w+=tr[x].tag;
        tr[x].tag=0;
    }
}
void push(int x)
{
    if(!isroot(x)) push(tr[x].fa);
    pushdown(x);
}
void splay(int x)
{
    push(x);
    while(!isroot(x))
    {
        int y=tr[x].fa; int z=tr[y].fa;
        if(!isroot(y))
        {
            if((tr[y].ch[0]==x)^(tr[z].ch[0]==y)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void access(int x)
{
    for(int y=0;x;y=x,x=tr[x].fa)
    {
        splay(x);
        tr[x].ch[1]=y;
    }
}
void cut(int x,int y) {access(x); splay(x); tr[x].ch[0]=0; tr[y].fa=0; tr[y].w+=-tr[x].w; tr[y].tag+=-tr[x].w;}
void link(int x,int y) {access(y); splay(y); access(x); splay(x); tr[x].fa=y; tr[y].w+=tr[x].w; tr[y].tag+=tr[x].w;}
void insert(int c)
{
    int nd=++tail; tr[nd].init(1); len[nd]=len[last]+1;
    int tmp=last; for(;tmp&&!ch[tmp][c];tmp=pa[tmp]) ch[tmp][c]=nd; 
    if(!tmp) {link(nd,root); pa[nd]=root;}
    else
    {
        int B=ch[tmp][c];
        if(len[B]==len[tmp]+1) {link(nd,B); pa[nd]=B;} 
        else
        {   
            int nB=++tail; tr[nB].init(0); 
            len[nB]=len[tmp]+1; 
            for(int i=0;i<26;i++) ch[nB][i]=ch[B][i];
            link(nB,pa[B]); cut(B,pa[B]); link(B,nB);  pa[nB]=pa[B]; pa[B]=nB;
            for(int i=tmp;i&&ch[i][c]==B;i=pa[i]) ch[i][c]=nB;
            pa[nd]=nB; link(nd,nB); 
        }
    }
    last=nd;
}
void getstr(int mask)
{
    for(int i=0;i<lens;i++)
    {
        mask=(mask*131+i)%lens;
        char t=str[i];
        str[i]=str[mask];
        str[mask]=t;
    }
}
int query()
{
    int tmp=root; 
    for(int i=0;i<lens;i++)
    {
        if(!ch[tmp][str[i]-'A']) return 0;
        tmp=ch[tmp][str[i]-'A'];
    }
    splay(tmp);
    return tr[tmp].w;
}
int main()
{
    int mask=0;
    scanf("%d",&q); scanf("%s",str);
    lens=strlen(str);
    for(int i=0;i<lens;i++) insert(str[i]-'A');
    while(q--)
    {
        scanf("%s",opt); int ret=0;
        scanf("%s",str); lens=strlen(str); getstr(mask);
        if(opt[0]=='A') for(int i=0;i<lens;i++) insert(str[i]-'A');
        else {ret=query(); printf("%d\n",ret); mask^=ret;}      
    }
    return 0;
}

二、维护子树大小

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int N=3000050;
int ccc;
struct node
{
    int fa,ch[2],size,ss,vr;
    void init(int x) {fa=0; ch[0]=ch[1]=0; size=x; ss=0; vr=x;}
}tr[N];
int q,tail=1,root=1,last=1,ch[N][26],len[N],pa[N],lens;
char str[N],opt[10];
void update(int x)
{
    int ls=tr[x].ch[0]; int rs=tr[x].ch[1];
    tr[x].size=tr[x].ss+tr[x].vr+tr[ls].size+tr[rs].size;
}
bool isroot(int x) {return tr[tr[x].fa].ch[0]!=x&&tr[tr[x].fa].ch[1]!=x;}
void rotate(int x)
{
    int y=tr[x].fa; int z=tr[y].fa;
    if(!isroot(y)) {if(tr[z].ch[0]==y) tr[z].ch[0]=x; else tr[z].ch[1]=x;}
    tr[x].fa=z;
    int l=(tr[y].ch[0]==x)?0:1; int r=l^1;
    tr[y].ch[l]=tr[x].ch[r]; tr[tr[x].ch[r]].fa=y;
    tr[x].ch[r]=y; tr[y].fa=x;
    update(y); update(x);
}
void splay(int x)
{
    while(!isroot(x))
    {
        int y=tr[x].fa; int z=tr[y].fa;
        if(!isroot(y))
        {
            if((tr[y].ch[0]==x)^(tr[z].ch[0]==y)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void access(int x)
{
    for(int y=0;x;y=x,x=tr[x].fa)
    {
        splay(x);
        tr[x].ss+=tr[tr[x].ch[1]].size;
        tr[x].ss-=tr[y].size;
        tr[x].ch[1]=y;
        update(x);
    }
}
void cut(int x,int y) {access(x); splay(x); tr[x].ch[0]=0; tr[y].fa=0; update(x);}
void link(int x,int y) {access(y); splay(y); access(x); splay(x); tr[x].fa=y; tr[y].ss+=tr[x].size; update(y);}
void insert(int c)
{
    int nd=++tail; tr[nd].init(1); len[nd]=len[last]+1;
    int tmp=last; for(;tmp&&!ch[tmp][c];tmp=pa[tmp]) ch[tmp][c]=nd; 
    if(!tmp) {link(nd,root); pa[nd]=root;}
    else
    {
        int B=ch[tmp][c];
        if(len[B]==len[tmp]+1) {link(nd,B); pa[nd]=B;} 
        else
        {   
            int nB=++tail; tr[nB].init(0); 
            len[nB]=len[tmp]+1; 
            for(int i=0;i<26;i++) ch[nB][i]=ch[B][i];
            link(nB,pa[B]); cut(B,pa[B]); link(B,nB);   pa[nB]=pa[B]; pa[B]=nB;
            for(int i=tmp;i&&ch[i][c]==B;i=pa[i]) ch[i][c]=nB;
            pa[nd]=nB; link(nd,nB);
        }
    }
    last=nd;
}
void getstr(int mask)
{
    for(int i=0;i<lens;i++)
    {
        mask=(mask*131+i)%lens;
        char t=str[i];
        str[i]=str[mask];
        str[mask]=t;
    }
}
int query()
{
    int tmp=root; 
    for(int i=0;i<lens;i++)
    {
        if(!ch[tmp][str[i]-'A']) return 0;
        tmp=ch[tmp][str[i]-'A'];
    }
    access(tmp); 
    return tr[tmp].ss+tr[tmp].vr;
}
int main()
{
    int mask=0;
    scanf("%d",&q); scanf("%s",str);
    lens=strlen(str);
    for(int i=0;i<lens;i++) insert(str[i]-'A');
    while(q--)
    {
        scanf("%s",opt); int ret=0;
        scanf("%s",str); lens=strlen(str); getstr(mask);
        if(opt[0]=='A') for(int i=0;i<lens;i++) insert(str[i]-'A');
        else {ret=query(); printf("%d\n",ret); mask^=ret;}      
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值