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的裸题,直接反着连边从1开始走起就好了,因为只是双向边,诸神眷顾的幻想乡 还更难一点,是双向边。
但是空间问题怎么解决,用map就好了。
#include
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=100007;
int i,j,k,l,n,m;
long long ans;
int a[maxn*2],first[maxn*2],last1[maxn*2],next[maxn*2],tot;
int last,num,np,nq,p,q,cc[maxn*2],cnt;
bool az[maxn];
map<int,int>son[maxn*40];
struct node{
int fa,len;
}t[maxn*40];
void add(int x,int y){
last1[++tot]=y;next[tot]=first[x];first[x]=tot;
}
int extend(int c,int last){
np=++num,p=last;
t[np].len=t[p].len+1;
while(p&&!son[p][c])son[p][c]=np,p=t[p].fa;
if(!p)t[np].fa=1;
else{
q=son[p][c];
if(t[p].len+1==t[q].len)t[np].fa=q;
else{
t[nq=++num]=t[q];
son[nq]=son[q];
t[nq].len=t[p].len+1;
t[q].fa=t[np].fa=nq;
while(p&&son[p][c]==q)son[p][c]=nq,p=t[p].fa;
}
}
last=np;
return last;
}
void dfs(int x,int y,int z){
int i,u=extend(a[x],z);
az[x]=1;
rep(i,x){
if(last1[i]!=y){
dfs(last1[i],x,u);
}
}
}
int main(){
freopen("route.in","r",stdin);
freopen("route.out","w",stdout);
scanf("%d",&n);
fo(i,1,n-1){
scanf("%d%d",&k,&l);a[k]++;a[l]++;cc[l]++;
add(l,k);
}
last=num=1;
dfs(1,0,1);
fo(i,2,num)ans+=t[i].len-t[t[i].fa].len;
printf("%lld\n", ans);
}