bzoj3926 [Zjoi2015]诸神眷顾的幻想乡
2018-01-30 11:01
351 查看
题目链接
分析:
先强调一点,题目中特意指出:太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过20个
翻译一下:最多有20个叶结点
知道这道题是用广义后缀自动机解决
广义SAM中包含了所有互异的子串
所以我们应该把尽量少,但是包含所有情况的字符串扔进SAM中
一开始我想的比较简单,只要把所有叶结点到根的字符串扔进去就可以了
但是这样显然包括所有的字符串情况(画个图就知道了,没法处理折线)
所以最后的解决方法就是把叶结点两两配对,
得到的字符串扔进SAM中
简单的做法:枚举每一个叶结点,以此为根,得到根到结点的路径,扔进SAM即可
最后的答案:
我们可以在dfs的过程中,直接insert结点即可
但是要注意插入不同的结点时,last是不一样的
所以我们需要专门记录一下
起始时:last=root
第一次写,insert操作比较容易写错
分析:
先强调一点,题目中特意指出:太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过20个
翻译一下:最多有20个叶结点
知道这道题是用广义后缀自动机解决
广义SAM中包含了所有互异的子串
所以我们应该把尽量少,但是包含所有情况的字符串扔进SAM中
一开始我想的比较简单,只要把所有叶结点到根的字符串扔进去就可以了
但是这样显然包括所有的字符串情况(画个图就知道了,没法处理折线)
所以最后的解决方法就是把叶结点两两配对,
得到的字符串扔进SAM中
简单的做法:枚举每一个叶结点,以此为根,得到根到结点的路径,扔进SAM即可
最后的答案:
∑ni=1dis[i]−dis[fa[i]]
意思就是从parenti走到i有多少种不同的方式(parenti和i有相同的前缀)tip
在以某一个结点为根dfs的时候,我们不用把每一个字符串记录下来再insert我们可以在dfs的过程中,直接insert结点即可
但是要注意插入不同的结点时,last是不一样的
所以我们需要专门记录一下
起始时:last=root
第一次写,insert操作比较容易写错
#include<cstdio> #include<cstring> #include<iostream> #define ll long long using namespace std; const int N=100010; int last=1,root=1,sz=1,ch[N*40][11],dis[N*40],fa[N*40]; int V ,n,c,st ,tot=0,in ; struct node{ int y,nxt; }; node way[N<<1]; void add(int u,int w) { tot++; way[tot].y=w;way[tot].nxt=st[u];st[u]=tot; tot++; way[tot].y=u;way[tot].nxt=st[w];st[w]=tot; } void insert(int x) { int now=ch[last][x],pre=last; if (now) { if (dis[now]==dis[pre]+1) last=now; else { int nows=++sz; dis[nows]=dis[pre]+1; memcpy(ch[nows],ch[now],sizeof(ch[now])); fa[nows]=fa[now]; fa[now]=nows; for (;pre&&ch[pre][x]==now;pre=fa[pre]) ch[pre][x]=nows; last=nows; } } else { now=++sz; dis[now]=dis[pre]+1; last=now; for (;pre&&!ch[pre][x];pre=fa[pre]) ch[pre][x]=now; if (!pre) fa[now]=root; else { int q=ch[pre][x]; if (dis[q]==dis[pre]+1) fa[now]=q; else { int nows=++sz; dis[nows]=dis[pre]+1; memcpy(ch[nows],ch[q],sizeof(ch[q])); fa[nows]=fa[q]; fa[q]=fa[now]=nows; for (;pre&&ch[pre][x]==q;pre=fa[pre]) ch[pre][x]=nows; } } } } void dfs(int now,int fa) { insert(V[now]); int t=last; //我们不用从头构造,只要记录一下在SAM上走到了哪里即可 for (int i=st[now];i;i=way[i].nxt) if (way[i].y!=fa) dfs(way[i].y,now),last=t; } int main() { scanf("%d%d",&n,&c); for (int i=1;i<=n;i++) scanf("%d",&V[i]); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); in[x]++; in[y]++; } for (int i=1;i<=n;i++) if (in[i]==1) last=root,dfs(i,0); ll ans=0; for (int i=1;i<=sz;i++) ans+=(ll)dis[i]-dis[fa[i]]; printf("%lld\n",ans); return 0; }
相关文章推荐
- 【BZOJ3926】诸神眷顾的幻想乡(ZJOI2015)-广义后缀自动机
- 【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机
- [BZOJ3926][ZJOI2015]诸神眷顾的幻想乡(广义后缀自动机)
- bzoj 3926: [Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)
- [BZOJ3926][Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)
- bzoj3926 [Zjoi2015]诸神眷顾的幻想乡
- [BZOJ3926]ZJOI2015诸神眷顾的幻想乡|后缀自动机
- 【bzoj3926】[Zjoi2015]诸神眷顾的幻想乡
- bzoj 3926: [Zjoi2015]诸神眷顾的幻想乡 后缀自动机
- 【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)
- bzoj 3926 [Zjoi2015]诸神眷顾的幻想乡
- 【bzoj3926- [Zjoi2015]诸神眷顾的幻想乡】广义sam
- BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡
- bzoj 3926 [Zjoi2015]诸神眷顾的幻想乡 后缀自动机
- 【bzoj3926】[Zjoi2015]诸神眷顾的幻想乡 后缀自动机
- 【bzoj3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机
- 【BZOJ3926】【Zjoi2015】诸神眷顾的幻想乡 后缀自动机
- bzoj3926 [Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)
- BZOJ.3926.[ZJOI2015]诸神眷顾的幻想乡(广义后缀自动机)
- BZOJ 3926 Zjoi2015 诸神眷顾的幻想乡 后缀自动机