Description
DQS的自家阳台上种着一棵颗粒饱满、颜色纯正的trie。
DQS的trie非常的奇特,它初始有n0个节点,n0-1条边,每条边上有一个字符。并且,它拥有极强的生长力:某个i时刻,某个节点就会新生长出一颗子树,它拥有si个节点且节点之间的边上有一个字符,并且新生长出来的子树也是一个树结构。然而因为是新长出来的,根据生活常识可知si必定不会大于i时刻之前的树的大小。
DQS定义trie的子串为从根节点(1号节点)往下走到所有节点所构成的字符串的所有的后缀。DQS身为一个单身doge,常常取出其中一个子串送给妹子,然而他并不希望送给妹子两个相同的子串,所以他非常关心当前trie的本质不同的子串数目。
DQS有时还会去商店购买子串,若他在商店看上某个子串,他希望得知这个子串是否在自家阳台的trie上已经出现,若出现则出现了多少次。如果出现了,他就可以直接回家取trie上的子串辣!
然而DQS身为一个蒟蒻,看着自家阳台的trie树一天天在长大,他被如此众多的节点弄得眼花缭乱,于是他找到了IOI2016Au的你。他会告诉你自家trie树的成长历程,他希望你能够对于每一次询问都做出正确回复。
Input
第一行输入一个整数id,代表测试点编号。
接下来一行输入一个整数n0,表示初始树的大小。
接下来n0-1行,每行两个整数u,v和一个字符c,表示u号节点和v号节点之间有一条边,边上的字母为c。
接下来输入m表示有m组操作。
对于每一组,第一行输入一个整数opt。
若opt=1,则是一组询问,询问当前trie的本质不同的子串数目是多少。
若opt=2,则后面跟两个整数rt,si,表示以点rt为根向下长出一个子树,大小为si。
接下来si-1行,每行两个整数u,v和一个字符c,表示u号节点和v号节点之间有一条边,边上的字母为c。若长出子树之前当前树的大小是n,则这si-1点的编号分别为n+1,n+2…n+si-1。
若opt=3,则是一组询问,后面输入一个字符串S,询问字符串S在当前trie中的出现次数。
Output
对于每个opt=1或3,输出一行表示答案。
Sample Input
1
4
1 2 a
1 3 b
2 4 b
6
1
2 2 4
2 5 b
2 6 c
5 7 b
1
3 ab
2 6 3
6 8 a
6 9 b
1
Sample Output
3
7
2
11
【数据范围及提示】
第一个询问,本质不同的子串是 a,b,ab。
第二个询问,本质不同的子串是 a,b,c,ab,ac,bb,abb。
第三个询问,ab出现次数是 2。
第四个询问,本质不同的子串是 a,b,c,ab,ac,ca,cb,bb,abb,aca,acb。
opt=1或3时对原树不做修改,只是询问。
每次opt=2,会增加si-1个节点,因为有一个节点是原树上作为新树的根出现的。
数据中,对于链的部分分,满足端点为根节点,每次新建子树都从尾部插入。
对于全部数据,保证从始至终每条边上的字符均为小写字母’a’或’b’或’c’。
n是最终树的大小,N<=100000,M<=100000,Si<=当前树的大小
HINT
Source
By Loi_DQS
裸SAM+LCT
抄一下2555以前写的代码
出题人强行放到trie上真是差评不已
总结一下就是这题是个SAM辣鸡题..
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define MAXN 200010
#define GET (ch>='0'&&ch<='9')
#define is_root(x) (tree[tree[x].fa].ch[0]!=x&&tree[tree[x].fa].ch[1]!=x)
using namespace std;
LL ans;
int n,m,top,tp;
bool vis[MAXN];
int sta[MAXN],num[MAXN],fa[MAXN];
char s[MAXN];
inline void in(int &x)
{
char ch=getchar();x=0;
while (!GET) ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();
}
struct Splay { int ch[2],fa,sum,flag; }tree[MAXN];
struct edge { int to,w; edge *next; }e[MAXN<<1],*prev[MAXN];
inline void insert(int u,int v,int w) { e[++top].to=v;e[top].w=w;e[top].next=prev[u];prev[u]=&e[top]; }
inline void add(int x,int v) { if (x) tree[x].sum+=v;tree[x].flag+=v; }
inline void push_down(int x)
{
if (tree[x].flag) add(tree[x].ch[0],tree[x].flag),add(tree[x].ch[1],tree[x].flag),tree[x].flag=0;
}
inline void rot(int x)
{
int y=tree[x].fa,z=tree[y].fa,l=(tree[y].ch[1]==x),r=l^1;
if (!is_root(y)) tree[z].ch[tree[z].ch[1]==y]=x;
tree[tree[x].ch[r]].fa=y;tree[y].fa=x;tree[x].fa=z;
tree[y].ch[l]=tree[x].ch[r];tree[x].ch[r]=y;
}
inline void Splay(int x)
{
tp=0;sta[++tp]=x;
for (int i=x;!is_root(i);i=tree[i].fa) sta[++tp]=tree[i].fa;
while (tp) push_down(sta[tp--]);
while (!is_root(x))
{
int y=tree[x].fa,z=tree[y].fa;
if (!is_root(y))
{
if ((tree[y].ch[0]==x)^(tree[z].ch[0]==y)) rot(x);
else rot(y);
}
rot(x);
}
}
inline void access(int x) { for (int i=0;x;i=x,x=tree[x].fa) Splay(x),tree[x].ch[1]=i; }
inline void make_root(int x) { access(x);Splay(x); }
inline void link(int x,int y) { tree[x].fa=y;make_root(y);add(y,tree[x].sum); }
inline void cut(int x) { make_root(x);add(tree[x].ch[0],-tree[x].sum);tree[tree[x].ch[0]].fa=0;tree[x].ch[0]=0; }
struct sam
{
int p,q,np,nq,cnt;
int a[MAXN][3],fa[MAXN],len[MAXN];
sam() { ++cnt; }
inline int insert(int c,int last)
{
p=last;np=++cnt;len[np]=len[p]+1;tree[np].sum=1;
while (!a[p][c]&&p) a[p][c]=np,p=fa[p];
if (!p) fa[np]=1,link(np,1),ans+=len[np]-len[1];
else
{
q=a[p][c];
if (len[q]==len[p]+1) fa[np]=q,link(np,q),ans+=len[np]-len[q];
else
{
ans-=len[q]-len[fa[q]];
nq=++cnt;len[nq]=len[p]+1;memcpy(a[nq],a[q],sizeof(a[q]));
fa[nq]=fa[q];link(nq,fa[nq]);fa[q]=fa[np]=nq;
cut(q);link(q,nq);link(np,nq);
ans+=len[nq]-len[fa[nq]];ans+=len[q]-len[nq];ans+=len[np]-len[nq];
while (a[p][c]==q) a[p][c]=nq,p=fa[p];
}
}
return np;
}
}sam;
void dfs(int x)
{
vis[x]=1;
for (edge *i=prev[x];i;i=i->next) if (!vis[i->to]) num[i->to]=sam.insert(i->w,num[x]),dfs(i->to);
}
int main()
{
freopen("data2.in","r",stdin);freopen("data2.out","w",stdout);
in(n);in(n);int opt,rt,sz,u,v;char c;
for (int i=1;i<n;i++)
{
in(u);in(v);c=' ';while (c<'a'||c>'c') c=getchar();
insert(u,v,c-'a');insert(v,u,c-'a');
}
num[1]=1;dfs(1);
for (in(m);m;m--)
{
in(opt);
if (opt==1) printf("%I64d\n",ans);
if (opt==2)
{
in(rt);in(sz);
for (int i=1;i<sz;i++)
{
in(u);in(v);c=' ';while (c<'a'||c>'c') c=getchar();
insert(u,v,c-'a');insert(v,u,c-'a');
}
dfs(rt);
}
if (opt==3)
{
scanf("%s",s+1);int l=strlen(s+1),now=1;
for (int i=1;now&&i<=l;i++) now=sam.a[now][s[i]-'a'];
if (!now) puts("0");
else Splay(now),printf("%d\n",tree[now].sum);
}
}
}