博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj3926- [Zjoi2015]诸神眷顾的幻想乡】广义sam
阅读量:4883 次
发布时间:2019-06-11

本文共 2617 字,大约阅读时间需要 8 分钟。

题意:给定一棵树,每个节点有一个颜色,问树上有多少种子串(定义子串为某两个点上的路径),保证叶子节点数<=20。n<=10^5

 

题解:

叶子节点小于等于20,考虑将每个叶子节点作为根把树给提起来形成一棵trie,然后定义这棵树的子串为从上到下的一个串(深度从浅到深)。

这样做我们可以发现每个子串必定是某棵trie上的一段直线。统计20棵树的不同子串只需要把它们建到一个自动机上就行了,相当于把20棵trie合并成一棵大的。

对于每个节点x,它贡献的子串数量是max[x]-min[x],又因为min[x]=max[fa]+1,则=max[x]-max[fa],就是step[x]-step[fa];
学会了怎样在sam上插入一颗trie,就直接记录一下父亲在sam上的节点作为p。注意每次都要新开一个点,不然会导致无意义的子串出现。

例如一棵树 (括号内为i颜色)    

              1(0)

              2(1)

        3(2)  4(3)

2是1的孩子,3和4都是2的孩子。在以1为根节点的时候插入了这棵trie,在以3为根节点的时候son[root][2]已经存在,如果用它来当现在的点的话就会让一棵trie接在另一棵的末位,导致无意义的子串出现,答案偏大。

 

1 #include
2 #include
3 #include
4 #include
5 using namespace std; 6 7 typedef long long LL; 8 const int N=20*100010; 9 int n,c,tot,len,last;10 int w[N],son[N][15],step[N],pre[N],first[N],cnt[N],id[N];11 struct node{12 int x,y,next;13 }a[2*N];14 15 void ins(int x,int y)16 {17 a[++len].x=x;a[len].y=y;18 a[len].next=first[x];first[x]=len;19 }20 21 int add_node(int x)22 {23 step[++tot]=x;24 return tot;25 }26 27 int extend(int p,int ch)28 {29 // int np;30 // if(son[p][ch]) return son[p][ch];31 // else np=add_node(step[p]+1);32 int np=add_node(step[p]+1);//debug 每次都要新开一个点33 34 while(p && !son[p][ch]) son[p][ch]=np,p=pre[p];35 if(p==0) pre[np]=1;36 else 37 {38 int q=son[p][ch];39 if(step[q]==step[p]+1) pre[np]=q;40 else 41 {42 int nq=add_node(step[p]+1);43 memcpy(son[nq],son[q],sizeof(son[q]));44 pre[nq]=pre[q];45 pre[np]=pre[q]=nq;46 while(son[p][ch]==q) son[p][ch]=nq,p=pre[p];47 }48 }49 last=np;50 return np;51 }52 53 void dfs(int x,int fa,int now)54 {55 int nt=extend(now,w[x]);56 // printf("%d\n",nt);57 for(int i=first[x];i;i=a[i].next)58 {59 int y=a[i].y;60 if(y!=fa) dfs(y,x,nt);61 }62 }63 64 int main()65 {66 freopen("a.in","r",stdin);67 scanf("%d%d",&n,&c);68 for(int i=1;i<=n;i++) scanf("%d",&w[i]);69 tot=0;len=0;70 memset(son,0,sizeof(son));71 memset(pre,0,sizeof(pre));72 memset(cnt,0,sizeof(cnt));73 memset(first,0,sizeof(first));74 step[++tot]=0;last=1;75 for(int i=1;i
%d\n",a[i].x,a[i].y);83 for(int i=1;i<=n;i++)84 {85 if(cnt[i]==1) dfs(i,0,1);86 }87 // for(int i=1;i<=tot;i++) printf("%d ",id[i]);printf("\n");88 LL ans=0;89 for(int i=1;i<=tot;i++) ans+=(LL)(step[i]-step[pre[i]]);90 printf("%lld\n",ans);91 return 0;92 }

 

转载于:https://www.cnblogs.com/KonjakJuruo/p/5831292.html

你可能感兴趣的文章
Web.config配置文件详解(新手必看)
查看>>
selenide总结
查看>>
selenium--控制浏览器和简单元素操作
查看>>
android spannableString 替换 textview 中部分文字
查看>>
java 引用
查看>>
关于Spring注解@Async引发其他注解失效
查看>>
关于学习的一些感悟
查看>>
算法提高 概率计算
查看>>
UVa 12716 - GCD XOR(筛法 + 找规律)
查看>>
Spring Cloud学习资料
查看>>
制作无广告启动盘
查看>>
python使用httplib2访问REST服务的例子
查看>>
经典代码(01)
查看>>
生成ico格式图标
查看>>
并查集hdu4424
查看>>
jdbc之分页查询
查看>>
sbrk and coreleft
查看>>
树型DP
查看>>
怎么在ubuntu上使用pidgin登陆QQ
查看>>
思维的惰性
查看>>