一道后缀自动机的好题,综合了后缀自动机一些重要的操作。
对于询问一,我们边建树边维护。
对于询问三,我们用一个LCT来维护。
(记得开long longQAQ)
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
struct splay
{
splay *fa,*ls,*rs;
int add_mark,val;
splay(int);
void push_down();
void add(int v);
}*null=new splay(0);
splay :: splay(int _=0)
{
fa=ls=rs=null;
add_mark=0;
val=_;
}
void splay :: add(int v)
{
val+=v;
add_mark+=v;
}
void splay :: push_down()
{
if(add_mark)
{
if(ls!=null) ls->add(add_mark);
if(rs!=null) rs->add(add_mark);
add_mark=0;
}
}
void right(splay *x)
{
splay *y=x->fa;
y->ls=x->rs;
x->rs->fa=y;
x->fa=y->fa;
x->rs=y;
if(y==y->fa->ls) y->fa->ls=x;
else if(y==y->fa->rs) y->fa->rs=x;
y->fa=x;
}
void left(splay *x)
{
splay *y=x->fa;
y->rs=x->ls;
x->ls->fa=y;
x->fa=y->fa;
x->ls=y;
if(y==y->fa->ls) y->fa->ls=x;
else if(y==y->fa->rs) y->fa->rs=x;
y->fa=x;
}
void push_down(splay *x)
{
if(x==x->fa->ls || x==x->fa->rs) push_down(x->fa);
x->push_down();
}
void splaying(splay *x)
{
push_down(x);
while(1)
{
splay *y=x->fa;
splay *z=y->fa;
if(x!=y->ls && x!=y->rs) break;
if(y!=z->ls && y!=z->rs)
{
if(x==y->ls) right(x);
else left(x);
break;
}
if(x==y->ls)
{
if(y==z->ls) right(y);
right(x);
}
else if(x==y->rs)
{
if(y==z->rs) left(y);
left(x);
}
}
}
void access(splay *x)
{
splay *y=null;
while(x!=null)
{
splaying(x);
x->rs=y;
y=x;
x=x->fa;
}
}
void cut(splay *x)
{
access(x);
splaying(x);
x->ls->fa=null;
x->ls=null;
}
void link(splay *x,splay *y)
{
cut(x);
x->fa=y;
}
struct sam
{
sam *parent,*son[26];
int max_len;
splay *tree;
sam(int _=0):parent(0x0),max_len(_)
{
memset(son,0,sizeof(son));
tree=new splay(0);
}
}*root=new sam,*mempool[1000000];
long long ans=0;
sam* my_insert(sam *p,int x)
{
/*if(p->son[x] && p->son[x]->max_len==p->max_len+1)
{
p->son[x]->tree->val++;
return p->son[x];
}*/
sam *np=new sam(p->max_len+1);
while(p && !p->son[x])
{
p->son[x]=np;
p=p->parent;
}
if(!p)
{
np->parent=root;
link(np->tree,root->tree);
}
else
{
sam *q=p->son[x];
if(p->max_len==q->max_len-1)
{
np->parent=q;
link(np->tree,q->tree);
}
else
{
sam *nq=new sam(p->max_len+1);
nq->parent=q->parent;
ans-=q->max_len-q->parent->max_len;
link(nq->tree,q->parent->tree);
memcpy(nq->son,q->son,sizeof(nq->son));
q->parent=nq;np->parent=nq;
ans+=q->max_len-q->parent->max_len;
ans+=nq->max_len-nq->parent->max_len;
link(q->tree,nq->tree);
link(np->tree,nq->tree);
push_down(q->tree);
nq->tree->val=q->tree->val;
while(p && p->son[x]==q)
{
p->son[x]=nq;
p=p->parent;
}
}
}
ans+=np->max_len-np->parent->max_len;
access(np->tree);
splaying(np->tree);
np->tree->add(1);
return np;
}
char s[1000000];
struct bian
{
int l,r,v;
}a[1000000];
int tot=0;
int fir[1000000];
int firc[1000000];
int nex[1000000];
int nexc[1000000];
void add_edge(int l,int r,char c,int cloc)
{
a[++tot].l=l;
a[tot].r=r;
a[tot].v=c;
if(firc[l]!=cloc)
{
firc[l]=cloc;
fir[l]=0;
}
if(nexc[tot]!=cloc)
{
nex[tot]=0;
nexc[tot]=cloc;
}
nex[tot]=fir[l];
fir[l]=tot;
}
void dfs(int u,int from,int v)
{
if(from!=0) mempool[u]=my_insert(mempool[from],v-'a');
for(int o=fir[u];o!=0;o=nex[o])
{
//cout<<a[o].r<<" ";
if(a[o].r!=from) dfs(a[o].r,u,a[o].v);
}
}
int search_ans()
{
sam *o=mempool[1];
for(int i=0;s[i];i++)
{
if(!o->son[s[i]-'a']) return 0;
o=o->son[s[i]-'a'];
}
push_down(o->tree);
return o->tree->val;
}
int main()
{
int id;
scanf("%d",&id);
int n;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int l,r;
char c[5];
scanf("%d%d%s",&l,&r,c);
add_edge(l,r,c[0],0);
add_edge(r,l,c[0],0);
}
mempool[1]=root;
dfs(1,0,0);
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int opt;
scanf("%d",&opt);
if(opt==1) printf("%lld\n",ans);
if(opt==2)
{
int rt,si;
scanf("%d%d",&rt,&si);
tot=0;
for(int j=1;j<si;j++)
{
int l,r;
char c[5];
scanf("%d%d%s",&l,&r,c);
add_edge(l,r,c[0],i);
add_edge(r,l,c[0],i);
}
dfs(rt,0,0);
}
if(opt==3)
{
scanf("%s",s);
printf("%d\n",search_ans());
}
}
return 0;
}