【LCA】HDU 5296 Annoying problem

通道: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 }
View Code

 

posted @ 2015-07-23 18:29  mithrilhan  阅读(231)  评论(0编辑  收藏  举报