bzoj3926: [Zjoi2015]诸神眷顾的幻想乡(广义SAM)
3926: [Zjoi2015]诸神眷顾的幻想乡
题目:传送门
简要题意:给出一棵树,每个点有编号和权值,问任意两个节点直接的路径上所有权值按顺序连起来形成的数列不同的个数(A到B和B到A是不一样的)
题解:
一道广义SAM的入门题目:和之前的生成魔咒差不多,主要在于对SAM的构造。
一开始想dfs把每条链插入,很显然发现是错的,不知道根而且会漏情况。
注意到题目的一个提示:叶子节点不超过20个
那么考虑每次把这些叶子节点当成根,然后建广义SAM,bfs直接搞,每次记得把last重置为root
然后直接更新ans啊:ans+=ch[i].dep-ch[ch[i].fail].dep(记得long long)
PS:状态数:20*100000*2
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 typedef long long LL; 8 struct SAM 9 { 10 int son[15],fail,dep; 11 SAM(){memset(son,0,sizeof(son));fail=dep=0;} 12 }ch[4100000];int root,cnt,la; 13 int a[110000],ru[110000],head,tail; 14 int add(int k) 15 { 16 int x=a[k]; 17 int p=la,np=++cnt;ch[np].dep=ch[p].dep+1; 18 while(p && ch[p].son[x]==0)ch[p].son[x]=np,p=ch[p].fail; 19 if(p==0)ch[np].fail=root; 20 else 21 { 22 int q=ch[p].son[x]; 23 if(ch[q].dep==ch[p].dep+1)ch[np].fail=q; 24 else 25 { 26 int nq=++cnt;ch[nq]=ch[q]; 27 ch[nq].dep=ch[p].dep+1; 28 ch[np].fail=ch[q].fail=nq; 29 while(p && ch[p].son[x]==q)ch[p].son[x]=nq,p=ch[p].fail; 30 } 31 } 32 return np; 33 } 34 int n,c; 35 struct trnode 36 { 37 int x,y,next; 38 }tr[210000];int len,last[110000]; 39 void ins(int x,int y) 40 { 41 len++;tr[len].x=x;tr[len].y=y; 42 tr[len].next=last[x];last[x]=len; 43 } 44 struct node 45 { 46 int x,w; 47 }list[210000];bool v[110000]; 48 void bt(int st) 49 { 50 la=root;memset(v,false,sizeof(v));v[st]=true; 51 node s;s.x=st;s.w=add(st); 52 list[1]=s;head=1;tail=2; 53 while(head!=tail) 54 { 55 s=list[head];int x=s.x; 56 for(int k=last[x];k;k=tr[k].next) 57 { 58 int y=tr[k].y; 59 if(v[y]==false) 60 { 61 v[y]=true; 62 node t;t.x=y; 63 la=s.w;t.w=add(y); 64 list[tail++]=t; 65 } 66 } 67 head++;//v[x]=false; 68 } 69 } 70 int main() 71 { 72 cnt=0;root=la=++cnt;scanf("%d%d",&n,&c);len=0;memset(last,0,sizeof(last)); 73 for(int i=1;i<=n;i++)scanf("%d",&a[i]);memset(ru,0,sizeof(ru)); 74 for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);ins(x,y);ins(y,x);ru[x]++;ru[y]++;} 75 for(int i=1;i<=n;i++)if(ru[i]==1)bt(i); 76 LL ans=0;for(int i=1;i<=cnt;i++)ans+=(LL(ch[i].dep-ch[ch[i].fail].dep)); 77 printf("%lld\n",ans); 78 return 0; 79 }