题目描述
A君准备在Z国进行一次旅行,Z国中有n个城市,城市从1到n进行编号,其中1号城市为Z国首都。Z国的旅行交通网由n-1条单向道路构成,并且从任何一个城市出发都可以通过旅行网到达首都。
一条旅行交通网中的旅行线路,可以用线路上所经过的城市来描述,如{v1,v2,v3,……,vm},它表示一条经过了m个城市的旅行路线,且城市vi到城市vi+1有一条单向道路相连。
两个城市是相似的,当且仅当他们所连接的道路数相同。
若两条路线{u1,u2,……,up}与{v1,v2,……,vq},若p=q且∀1 ≤ i ≤ p,城市 u i 与 v i 是相似的,则 A君认为这两条旅行路线也是相似的。
现在A君想知道共有多少种不同的旅行路线,相似的若干条旅行路线只算一种。
trie上建sam
trie上建广义sam裸题
#include<cstdio>
#include<algorithm>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
map<int,int> g[maxn*2];
map<int,int>::iterator it;
ll size[maxn*2];
int fail[maxn*2],step[maxn*2],b[maxn],a[maxn*2];
int h[maxn],go[maxn*2],next[maxn*2],d[maxn],dl[maxn],sum[maxn*2];
int i,j,k,l,t,n,m,tot,top,ans,last,head,tail,now;
void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void ins(int c){
int p=last;
if (g[p][c]){
int q=g[p][c];
if (step[q]==step[p]+1) last=q;
else{
int i,nq=++tot;
size[nq]=1;
step[nq]=step[p]+1;
g[nq]=g[q];
fail[nq]=fail[q];
fail[q]=nq;
while (p&&g[p][c]==q){
g[p][c]=nq;
p=fail[p];
}
last=nq;
}
return;
}
int np=++tot;
size[np]=1;
step[np]=step[p]+1;
while (p&&g[p][c]==0){
g[p][c]=np;
p=fail[p];
}
if (!p) fail[np]=1;
else{
int q=g[p][c];
if (step[q]==step[p]+1) fail[np]=q;
else{
int nq=++tot;
size[nq]=1;
step[nq]=step[p]+1;
g[nq]=g[q];
fail[nq]=fail[q];
fail[q]=nq;
fail[np]=nq;
while (p&&g[p][c]==q){
g[p][c]=nq;
p=fail[p];
}
}
}
last=np;
}
int main(){
freopen("route.in","r",stdin);freopen("route.out","w",stdout);
scanf("%d",&n);
fo(i,1,n-1){
scanf("%d%d",&j,&k);
d[j]++;d[k]++;
add(k,j);
}
tot=1;
dl[tail=1]=1;
last=1;
ins(d[1]);
b[1]=last;
while (head<tail){
now=dl[++head];
t=h[now];
while (t){
last=b[now];
ins(d[go[t]]);
b[go[t]]=last;
dl[++tail]=go[t];
t=next[t];
}
}
fo(i,1,tot) sum[step[i]]++;
fo(i,1,tot) sum[i]+=sum[i-1];
fd(i,tot,1) a[sum[step[i]]--]=i;
fd(i,tot,1){
t=a[i];
it=g[t].begin();
while (it!=g[t].end()){
j=(*it).second;
size[t]+=size[j];
it++;
}
}
printf("%lld\n",size[1]);
}