zoukankan      html  css  js  c++  java
  • 【BZOJ4545】DQS的trie 后缀自动机+LCT

    【BZOJ4545】DQS的trie

    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<=当前树的大小

    题解:本题就是3998和2555的结合体,没做过的直接去做那两题吧。

    对于第一问,我们可以动态维护所有点的mx[i]-mx[pre]之和,对于第二问,用LCT维护pre树,并将 插入一棵子树,求一个点的子树大小 变成 修改一条链上的权值,查询一个点的值 即可。

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=400010;
    typedef long long ll;
    int n,m,tot,len,cnt;
    int to[maxn],next[maxn],val[maxn],head[maxn],pos[maxn];
    ll ans;
    char str[maxn];
    namespace LCT
    {
    	struct node
    	{
    		int ch[2],fa;
    		ll tag,val;
    	}s[maxn];
    	int st[maxn],top;
    	inline bool isr(int x) {return (x!=s[s[x].fa].ch[0])&&(x!=s[s[x].fa].ch[1]);}
    	inline void pushdown(int x)
    	{
    		if(s[x].tag)
    		{
    			if(s[x].ch[0])	s[s[x].ch[0]].val+=s[x].tag,s[s[x].ch[0]].tag+=s[x].tag;
    			if(s[x].ch[1])	s[s[x].ch[1]].val+=s[x].tag,s[s[x].ch[1]].tag+=s[x].tag;
    			s[x].tag=0;
    		}
    	}
    	inline void rotate(int x)
    	{
    		int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]);
    		if(!isr(y))	s[z].ch[y==s[z].ch[1]]=x;
    		s[x].fa=z,s[y].fa=x,s[y].ch[d]=s[x].ch[d^1];
    		if(s[x].ch[d^1])	s[s[x].ch[d^1]].fa=y;
    		s[x].ch[d^1]=y;
    	}
    	inline void updata(int x)
    	{
    		int y=x;
    		st[top=1]=x;
    		while(!isr(y))	y=s[y].fa,st[++top]=y;
    		while(top)	pushdown(st[top--]);
    	}
    	inline void splay(int x)
    	{
    		updata(x);
    		while(!isr(x))
    		{
    			int y=s[x].fa,z=s[y].fa;
    			if(!isr(y))
    			{
    				if((x==s[y].ch[0])^(y==s[z].ch[0]))	rotate(x);
    				else	rotate(y);
    			}
    			rotate(x);
    		}
    	}
    	inline void access(int x)
    	{
    		for(int y=0;x;splay(x),s[x].ch[1]=y,y=x,x=s[x].fa);
    	}
    	inline void link(int x,int y)
    	{
    		access(x),splay(x),s[y].fa=x,s[x].val+=s[y].val,s[x].tag+=s[y].val;
    	}
    	inline void cut(int x)
    	{
    		access(x),splay(x),s[s[x].ch[0]].val-=s[x].val,s[s[x].ch[0]].tag-=s[x].val;
    		s[s[x].ch[0]].fa=0,s[x].ch[0]=0;
    	}
    }
    namespace SAM
    {
    	int ch[maxn][26],pre[maxn],mx[maxn];
    	char str[maxn];
    	inline int extend(int p,int x)
    	{
    		int np=++tot;
    		mx[np]=mx[p]+1,LCT::s[np].val=1;
    		for(;p&&!ch[p][x];p=pre[p])	ch[p][x]=np;
    		if(!p)	pre[np]=1,ans+=mx[np],LCT::link(1,np);
    		else
    		{
    			int q=ch[p][x];
    			if(mx[q]==mx[p]+1)	pre[np]=q,ans+=mx[np]-mx[q],LCT::link(q,np);
    			else
    			{
    				int nq=++tot;	mx[nq]=mx[p]+1;
    				ans-=mx[q]-mx[pre[q]];
    				LCT::cut(q);
    				pre[nq]=pre[q],pre[np]=pre[q]=nq;
    				ans+=mx[nq]-mx[pre[nq]]+mx[np]-mx[pre[np]]+mx[q]-mx[pre[q]];
    				LCT::link(pre[nq],nq),LCT::link(pre[q],q),LCT::link(pre[np],np);
    				memcpy(ch[nq],ch[q],sizeof(ch[q]));
    				for(;p&&ch[p][x]==q;p=pre[p])	ch[p][x]=nq;
    			}
    		}
    		return np;
    	}
    	inline void query()
    	{
    		scanf("%s",str),len=strlen(str);
    		int i,p=1;
    		for(i=0;i<len&&p;i++)	p=ch[p][str[i]-'a'];
    		if(!p)	puts("0");
    		else
    		{
    			LCT::updata(p);
    			printf("%lld
    ",LCT::s[p].val);
    		}
    	}
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    void dfs(int x,int fa)
    {
    	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa)	pos[to[i]]=SAM::extend(pos[x],val[i]),dfs(to[i],x);
    	head[x]=-1;
    }
    inline void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    }
    int main()
    {
    	rd(),n=rd();
    	int i,a,b,c,d,op;
    	tot=1,pos[1]=1;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)	a=rd(),b=rd(),scanf("%s",str),add(a,b,str[0]-'a'),add(b,a,str[0]-'a');
    	dfs(1,0);
    	m=rd();
    	for(i=1;i<=m;i++)
    	{
    		op=rd();
    		if(op==1)	printf("%lld
    ",ans);
    		if(op==2)
    		{
    			c=rd(),d=rd();
    			while(--d)	a=rd(),b=rd(),scanf("%s",str),add(a,b,str[0]-'a'),add(b,a,str[0]-'a');
    			dfs(c,0);
    		}
    		if(op==3)	SAM::query();
    	}
    	return 0;
    }//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

     

  • 相关阅读:
    poj3278 Catch That Cow
    poj2251 Dungeon Master
    poj1321 棋盘问题
    poj3083 Children of the Candy Cor
    jvm基础知识—垃圾回收机制
    jvm基础知识1
    java面试基础必备
    java soket通信总结 bio nio aio的区别和总结
    java scoket aIO 通信
    java scoket Blocking 阻塞IO socket通信四
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7859563.html
Copyright © 2011-2022 走看看