B 蒜头君的树
|
问题描述
蒜头君有一棵有根树,树的每一边都有边权,蒜头君想知道任意两点间最短距离之和为多少。 另外,由于各种原因,蒜头君的树的边的边权会发生若干次改变,蒜头君想让你告诉他,每一 次改变后,任意两点间最短距离之和为多少?
输入格式
输出格式
r
样例输入
4
1 1
1 1
1 1
1
2 2
样例输出
9
12
【题目分析】
算法 1
每次 O(N2) 查询每两对点的距离,时间复杂度 O(N2M),期望得分 30 分。
算法 2
考虑每条边会在答案中被计算几次,假设删除一条边后所得到的连通分量的大小为 a 和 b,
则 这条边会被统计 a*b 次,可以用一遍 DFS 得到每个点及其子节点的总数,然后可以得
到 a 和 b,对于每个询问都做一遍 DFS。时间复杂度 O(N ∗ M),期望得分 70 分。
算法 3
对于任意一条边 i, 设该边长度为 L[i], 连的儿子节点为 x。
size[x]为 x 为根的子树中节点的总数。 那么 i 号边被公交线路经过的次数为 size[x]*(n-size[x])
i 号边对答案的贡献为 TotLen+=L[i]* size[x]*(n-size[x])
对于每个询问,只考虑修改每一条边会变成什么样,则可以 O(1) 处理每一个询问,时间复
杂度 O(N + M),期望得分 100 分。
每次 O(N2) 查询每两对点的距离,时间复杂度 O(N2M),期望得分 30 分。
算法 2
考虑每条边会在答案中被计算几次,假设删除一条边后所得到的连通分量的大小为 a 和 b,
则 这条边会被统计 a*b 次,可以用一遍 DFS 得到每个点及其子节点的总数,然后可以得
到 a 和 b,对于每个询问都做一遍 DFS。时间复杂度 O(N ∗ M),期望得分 70 分。
算法 3
对于任意一条边 i, 设该边长度为 L[i], 连的儿子节点为 x。
size[x]为 x 为根的子树中节点的总数。 那么 i 号边被公交线路经过的次数为 size[x]*(n-size[x])
i 号边对答案的贡献为 TotLen+=L[i]* size[x]*(n-size[x])
对于每个询问,只考虑修改每一条边会变成什么样,则可以 O(1) 处理每一个询问,时间复
杂度 O(N + M),期望得分 100 分。
【参考代码】
1 #include<cstdio> 2 #include<cctype> 3 #define ll long long 4 #define maxn 100003 5 using namespace std; 6 int n, m, tot; 7 int Last[maxn], Fa[maxn], Size[maxn], Num[maxn]; 8 ll ans; 9 ll F[maxn]; 10 char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf; 11 struct node { 12 int End, Next, Len; 13 }Edge[maxn << 1]; 14 namespace Ironclad_Programming { 15 #define R register int 16 #define For(i, s, n) for (R i = s; i <= n; ++ i) 17 #define Getch() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1 ++) 18 inline int read() { 19 int x = 0, f = 1; 20 char ch = Getch(); 21 while(!isdigit(ch)){if (ch == '-')f = -1; ch = Getch();} 22 while(isdigit(ch))x = x * 10 + (ch ^ 48), ch = Getch(); 23 return x * f; 24 } 25 inline void Add(int x, int y, int z) { 26 Edge[++ tot].End = y; 27 Edge[tot].Len = z; 28 Edge[tot].Next = Last[x]; 29 Last[x] = tot; 30 } 31 void ini() { 32 n = read(); 33 For (i, 2, n) { 34 int x, y; 35 x = read(), y = read(); 36 Add(x, i, y); 37 Add(i, x, y); 38 Fa[i] = x; 39 Num[i] = tot; 40 } 41 } 42 namespace solve { 43 void DFS(int x) { 44 ++ Size[x]; 45 for (R i = Last[x]; i; i = Edge[i].Next) { 46 int y = Edge[i].End; 47 if (y ^ Fa[x]) { 48 DFS(y); 49 ans += 1LL * Edge[i].Len * F[y]; 50 Size[x] += Size[y]; 51 } 52 } 53 F[x] = 1LL * Size[x] * (n - Size[x]); 54 } 55 void Del_Back() { 56 m = read(); 57 For (i, 1, m) { 58 int x, y; 59 x = read(), y = read();; 60 ans += 1LL * (y - Edge[Num[x]].Len) * F[x]; 61 Edge[Num[x]].Len = y; 62 printf("%lld\n", ans); 63 } 64 } 65 void executive() { 66 DFS(1); 67 printf("%lld\n", ans); 68 Del_Back(); 69 } 70 } 71 void Main() { 72 ini(); 73 solve::executive(); 74 } 75 #undef R 76 #undef For 77 #undef Getch 78 } 79 int main() { 80 Ironclad_Programming::Main(); 81 return 0; 82 }