旅行路线
Time Limit: 20 Sec Memory Limit: 256 MBDescription
Input
Output
仅一行一个整数表示答案。
Sample Input
3
2 1
3 1
Sample Output
3
HINT
Main idea
将每个点的入度作为标识,问从叶节点到根有几个本质不同的串。
Solution
我们先考虑暴力的写法,显然无重复的话是答案是ΣDep[i],那么我们构建出一棵树,然后从任意两个点暴力往上判断找到最长相同的长度,然后减去这个长度即可。
我们发现这个算法慢在哪里?就是一步步判断太慢了!对于这种问题,我们显然可以使用倍增。
我们用字符串的哈希值来判断字符串是否相同,那么就记录一个hash[u][i]表示从u到往上跳(2^i)-1的哈希值,然后我们按照每个点到根的哈希值排序,显然得到的序列会满足:哈希值有相同的必然会在一起,若相同的长则会更接近。
然后我们O(n)比较相邻两个的哈希值,用倍增来跳,找到最长长度减去即可。
Code
1 #include<iostream>
2 #include<algorithm>
3 #include<cstdio>
4 #include<cstring>
5 #include<cstdlib>
6 #include<cmath>
7 using namespace std;
8 typedef long long s64;
9 const int ONE = 100005;
10 const int INF = 214783640;
11 const int P = 21;
12
13 int n;
14 int x,y;
15 int Input[ONE];
16 int Dep[ONE],id[ONE];
17 int f[ONE][22];
18 s64 Q[ONE],hash[ONE][22];
19 int next[ONE],first[ONE],go[ONE],tot;
20 s64 Ans;
21
22 int get()
23 {
24 int res=1,Q=1; char c;
25 while( (c=getchar())<48 || c>57)
26 if(c=='-')Q=-1;
27 if(Q) res=c-48;
28 while((c=getchar())>=48 && c<=57)
29 res=res*10+c-48;
30 return res*Q;
31 }
32
33 int Add(int u,int v)
34 {
35 next[++tot]=first[u]; first[u]=tot; go[tot]=v;
36 }
37
38 void Dfs(int u)
39 {
40 hash[u][0] = Input[u];
41
42 for(int i=0;i<=P-1;i++)
43 {
44 f[u][i+1] = f[f[u][i]][i];
45 hash[u][i+1] = hash[u][i] + hash[f[u][i]][i] * Q[i];
46 }
47
48 for(int e=first[u];e;e=next[e])
49 {
50 int v=go[e];
51 f[v][0] = u;
52 Dep[v] = Dep[u] + 1;
53 Dfs(v);
54 }
55 }
56
57 bool cmp(int x,int y)
58 {
59 for(int i=P-1;i>=0;i--)
60 if(Dep[x]>=(1<<i) && hash[x][i] == hash[y][i])
61 {
62 x = f[x][i];
63 y = f[y][i];
64 }
65 return hash[x][0] < hash[y][0];
66 }
67
68 int Same(int x,int y)
69 {
70 int res=0;
71 for(int i=P-1;i>=0;i--)
72 if(Dep[x]>=(1<<i) && hash[x][i] == hash[y][i])
73 {
74 x = f[x][i];
75 y = f[y][i];
76 res += (1<<i);
77 }
78 return res;
79 }
80
81 int main()
82 {
83 n=get();
84 for(int i=1;i<=n;i++) id[i]=i;
85 for(int i=1;i<n;i++)
86 {
87 x=get(); y=get();
88 Add(y,x);
89 Input[x]++; Input[y]++;
90 }
91
92 Q[0] = 1e9+7;
93 for(int i=1;i<=P;i++) Q[i] = Q[i-1] * Q[i-1];
94
95 Dep[1]=1; Dfs(1);
96 sort(id+1,id+n+1,cmp);
97
98 Ans = Dep[id[1]];
99 for(int i=2;i<=n;i++)
100 {
101 Ans += Dep[id[i]] - Same(id[i],id[i-1]);
102 }
103
104 printf("%lld",Ans);
105 }