B 蒜头君的树

时间限制 : - MS   空间限制 : - KB 
评测说明 : 2s,256m
问题描述

蒜头君有一棵有根树,树的每一边都有边权,蒜头君想知道任意两点间最短距离之和为多少。 另外,由于各种原因,蒜头君的树的边的边权会发生若干次改变,蒜头君想让你告诉他,每一 次改变后,任意两点间最短距离之和为多少?

输入格式

输出格式

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 分。

【参考代码】
 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
", ans);
63             }
64         }
65         void executive() {
66             DFS(1);
67             printf("%lld
", 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 }
原文地址:https://www.cnblogs.com/Limbo-To-Heaven/p/11637261.html