bzoj 2555: SubString

显然,在后缀自动机的后缀树上插入一个后缀后,此时表示整串的节点(np)到根的所有节点,其表示的串作为子串的出现次数都要+1;发现需要链修改,动态连边/删边,因此用LCT维护

注意:虽然没明确写,但根据讨论区以及做题情况,此题字符集只有AB两个字母

错误记录:没有msk^=res

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 using namespace std;
  5 int Add(int a,int b)    {return a+b;}
  6 int Add(int a,int b,int c)    {return a+b+c;}
  7 int Mul(int a,int b)    {return a*b;}
  8 namespace LCT
  9 {
 10 const int N=1200000;
 11 struct Node
 12 {
 13     Node *ch[2],*fa;
 14     bool rev;
 15     int addv;
 16     int dat,sz;
 17     void upd()    {sz=(ch[0]?ch[0]->sz:0)+1+(ch[1]?ch[1]->sz:0);}
 18     void padd(int x)    {addv=Add(addv,x);dat=Add(dat,x);}
 19     void pd()
 20     {
 21         if(rev)
 22         {
 23             swap(ch[0],ch[1]);
 24             if(ch[0])    ch[0]->rev^=1;
 25             if(ch[1])    ch[1]->rev^=1;
 26             rev=0;
 27         }
 28         if(addv)
 29         {
 30             if(ch[0])    ch[0]->padd(addv);
 31             if(ch[1])    ch[1]->padd(addv);
 32             addv=0;
 33         }
 34     }
 35     bool isroot()    {return (!fa)||(this!=fa->ch[0]&&this!=fa->ch[1]);}
 36     bool gson()    {return this==fa->ch[1];}
 37     void rot()//将自身向上旋,要求已经完成下传标记
 38     {
 39         bool d=gson();Node *f=fa;
 40         fa=f->fa;if(!f->isroot())    f->fa->ch[f->gson()]=this;
 41         f->ch[d]=ch[!d];if(ch[!d])    ch[!d]->fa=f;
 42         f->fa=this;ch[!d]=f;
 43         f->upd();upd();
 44     }
 45 }nodes[N+100];
 46 Node *st[N+100];int top;
 47 int mem;
 48 Node *getnode()
 49 {
 50     Node *t=nodes+mem++;t->sz=1;//t->ch[0]=t->ch[1]=t->fa=0;t->rev=t->addv=t->dat=0;
 51     return t;
 52 }
 53 void solvetag(Node *o)
 54 {
 55     while(!o->isroot())    st[++top]=o,o=o->fa;
 56     st[++top]=o;
 57     while(top)    st[top--]->pd();
 58 }
 59 void splay(Node *o)
 60 {
 61     solvetag(o);
 62     for(;!o->isroot();o->rot())
 63         if(!o->fa->isroot())
 64             o->gson()==o->fa->gson()?o->fa->rot():o->rot();
 65 }
 66 void acc(Node *o)
 67 {
 68     for(Node *lst=0;o;lst=o,o=o->fa)
 69         splay(o),o->ch[1]=lst,o->upd();
 70 }
 71 void mtop(Node *o)    {acc(o);splay(o);o->rev^=1;}
 72 void link(Node *x,Node *y)    {acc(x);splay(x);x->fa=y;}//保证x是根,使x成为y子节点
 73 void cut(Node *x)    {acc(x);splay(x);x->ch[0]->fa=0;x->ch[0]=0;}//断开x与父亲
 74 void add(Node *y,int t)    {acc(y);splay(y);y->padd(t);}//y到根路径+t
 75 int query(Node *y)    {splay(y);return y->dat;}//查询y单点的权值
 76 }
 77 using LCT::Node;using LCT::link;using LCT::getnode;using LCT::cut;using LCT::query;
 78 namespace SAM
 79 {
 80 int mem,np,root;
 81 int len[1200100],fa[1200100],trans[1200100][3];
 82 Node *nd[1200100];
 83 void append(int c)
 84 {
 85     int p=np;np=++mem;len[np]=len[p]+1;nd[np]=getnode();
 86     for(;p&&trans[p][c]==0;p=fa[p])    trans[p][c]=np;
 87     if(!p)    link(nd[np],nd[root]),fa[np]=root;
 88     else
 89     {
 90         int q=trans[p][c];
 91         if(len[q]==len[p]+1)    link(nd[np],nd[q]),fa[np]=q;
 92         else
 93         {
 94             int nq=++mem;nd[nq]=getnode();nd[nq]->dat=query(nd[q]);
 95             cut(nd[q]);link(nd[nq],nd[fa[q]]);link(nd[q],nd[nq]);link(nd[np],nd[nq]);
 96             fa[nq]=fa[q];fa[q]=fa[np]=nq;
 97             memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+1;
 98             for(;p&&trans[p][c]==q;p=fa[p])    trans[p][c]=nq;
 99         }
100     }
101     LCT::add(nd[np],1);
102 }
103 int query(const char *ss,int len)
104 {
105     int now=root,i;
106     for(i=0;i<len;i++)
107     {
108         now=trans[now][ss[i]-'A'];
109         if(!now)    return 0;
110     }
111     return query(nd[now]);
112 }
113 }
114 char tmp[3000100],ttt[10];int len,q;
115 void decode(int msk)
116 {
117     for(int j=0;j<len;j++)
118     {
119         msk=(msk*131+j)%len;
120         swap(tmp[j],tmp[msk]);
121     }
122 }
123 int main()
124 {
125     int msk=0,res,i;SAM::np=SAM::root=++SAM::mem;SAM::nd[SAM::root]=getnode();
126     scanf("%d",&q);
127     scanf("%s",tmp);len=strlen(tmp);
128     for(i=0;i<len;i++)    SAM::append(tmp[i]-'A');
129     while(q--)
130     {
131         scanf("%s",ttt);
132         if(ttt[0]=='A')
133         {
134             scanf("%s",tmp);len=strlen(tmp);decode(msk);
135             for(i=0;i<len;i++)    SAM::append(tmp[i]-'A');
136         }
137         else if(ttt[0]=='Q')
138         {
139             scanf("%s",tmp);len=strlen(tmp);decode(msk);
140             res=SAM::query(tmp,len);msk^=res;printf("%d\n",res);
141         }
142     }
143     return 0;
144 }

 

posted @ 2018-05-10 20:29  hehe_54321  阅读(287)  评论(0编辑  收藏  举报
AmazingCounters.com