通道:http://acm.hdu.edu.cn/showproblem.php?pid=5296
题意:给一棵n个节点的树,再给q个操作,初始集合S为空,每个操作要在一个集合S中删除或增加某些点,输出每次操作后:要使得集合中任意两点互可达所耗最小需要多少权值。(记住只能利用原来给的树边。给的树边已经有向。10万个点,10万个操作)
思路:
代码:
1 #pragma comment(linker, "/STACK:102400000,102400000") 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <set> 6 #include <cmath> 7 8 using namespace std; 9 10 const int MAX_N = 200007; 11 12 struct Node { 13 int v, w, nxt; 14 Node () { 15 16 } 17 Node (int _v, int _w, int _n) { 18 v = _v; 19 w = _w; 20 nxt = _n; 21 } 22 }; 23 24 int head[MAX_N], edgecnt, now; 25 int dfn[MAX_N], id[MAX_N << 1], dep[MAX_N << 1]; 26 int dis[MAX_N], dp[MAX_N << 1][24];; 27 Node G[MAX_N << 2]; 28 29 void Clear() { 30 edgecnt = 0, now = 0; 31 memset(head, -1, sizeof head); 32 memset(dis, 0, sizeof dis); 33 } 34 35 void add(int u, int v, int w) { 36 G[edgecnt] = Node(v, w, head[u]); 37 head[u] = edgecnt++; 38 } 39 40 int pa[23][MAX_N]; 41 42 void dfs(int u, int fa, int d) { 43 dep[u] = d; 44 pa[0][u] = fa; 45 dfn[u] = now, id[now++] = u; 46 for (int i = head[u]; ~i; i = G[i].nxt) { 47 int v = G[i].v; 48 if (v != fa) { 49 dis[v] = dis[u] + G[i].w; 50 dfs(v, u, d + 1); 51 } 52 } 53 } 54 55 int lca(int u, int v) { 56 if (dep[u] > dep[v]) swap(u, v); 57 for (int k = 0; k < 23; ++k) { 58 if ((dep[v] - dep[u]) >> k & 1) { 59 v = pa[k][v]; 60 } 61 } 62 if (u == v) return u; 63 for (int k = 23 - 1; k >= 0; --k) { 64 if (pa[k][v] != pa[k][u]) { 65 v = pa[k][v]; 66 u = pa[k][u]; 67 } 68 } 69 return pa[0][u]; 70 } 71 72 set<int> s; 73 int n, m; 74 75 int cal(int u) { 76 if (s.empty()) return 0; 77 set<int>::iterator it = s.lower_bound(u); 78 int y = *it; --it; int x = *it; 79 x = id[x], y = id[y]; 80 int l = *s.begin(), r = *s.rbegin(); 81 if (u < l || r < u) x = id[l], y = id[r]; 82 u = id[u]; 83 return dis[u] - dis[lca(x, u)] - dis[lca(y, u)] + dis[lca(x, y)]; 84 } 85 86 int main() { 87 int T, cas = 0; 88 scanf("%d", &T); 89 while (T-- > 0) { 90 Clear(); 91 s.clear(); 92 scanf("%d%d", &n, &m); 93 for (int i = 1; i < n; ++i) { 94 int u, v, w; 95 scanf("%d%d%d", &u, &v, &w); 96 add(u, v, w), add(v, u, w); 97 } 98 dfs(1, -1, 0); 99 for (int k = 0; k + 1 < 23; ++k) { 100 for (int v = 1; v <= n; ++v) { 101 if (pa[k][v] < 0) pa[k + 1][v] = -1; 102 else pa[k + 1][v] = pa[k][pa[k][v]]; 103 } 104 } 105 printf("Case #%d:\n", ++cas); 106 int ans = 0; 107 for (int i = 0; i < m; ++i) { 108 int t, v; 109 scanf("%d%d", &t, &v); 110 v = dfn[v]; 111 if (1 == t) { 112 if (!s.count(v)) { 113 ans += cal(v); 114 s.insert(v); 115 } 116 } else { 117 if (s.count(v)) { 118 s.erase(v); 119 ans -= cal(v); 120 } 121 } 122 printf("%d\n", ans); 123 } 124 } 125 return 0; 126 }
时间: 2024-10-13 05:14:50