HDU 3078:Network(LCA之tarjan)

http://acm.hdu.edu.cn/showproblem.php?pid=3078

题意:给出n个点n-1条边m个询问,每个点有个权值,询问中有k,u,v,当k = 0的情况是将u的权值修改成v,当k不为0的情况是问u和v的路径中权值第k大的点的权值是多少。

思路:比较暴力的方法,可能数据太水勉强混过去了。对于每一个询问的时候保留两个点之间的lca,还有计算出两个点之间的点的个数(询问的时候如果点的个数小于k就不用算了),然后tarjan算完之后对每个询问再暴力路径上的每个点放进vector排序输出第k大..

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <queue>
  6 #include <cmath>
  7 #include <map>
  8 #include <vector>
  9 using namespace std;
 10 #define N 80010
 11 #define M 30010
 12 struct node
 13 {
 14     int u, v, next;
 15 }edge[N*2];
 16 struct P
 17 {
 18     int u, v, next, num, k, lca;
 19 }Edge[M*2];
 20 int n, m, tot, Tot, head[N], Head[N], a[N], fa[N], dis[N];
 21 bool vis[N];
 22 vector<int> vec;
 23 
 24 void init()
 25 {
 26     tot = Tot = 0;
 27     memset(head, -1, sizeof(head));
 28     memset(Head, -1, sizeof(Head));
 29     memset(dis, -1, sizeof(dis));
 30     memset(vis, false, sizeof(vis));
 31     for(int i = 1; i <= n; i++) fa[i] = i;
 32 }
 33 
 34 void add(int u, int v)
 35 {
 36     edge[tot].u = u; edge[tot].v = v; edge[tot].next = head[u]; head[u] = tot++;
 37 }
 38 
 39 void Add(int u, int v, int k)
 40 {
 41     Edge[Tot].k = k; Edge[Tot].u = u; Edge[Tot].v = v; Edge[Tot].next = Head[u]; Edge[Tot].num = 0; Edge[Tot].lca = -1; Head[u] = Tot++;
 42 }
 43 
 44 int Find(int x)
 45 {
 46     while(x != fa[x]) x = fa[x];
 47     return x;
 48 }
 49 
 50 void Merge(int u, int v)
 51 {
 52     u = Find(u), v = Find(v);
 53     fa[v] = u;
 54 }
 55 
 56 void tarjan(int u)
 57 {
 58     vis[u] = true;
 59     for(int i = head[u]; ~i; i = edge[i].next) {
 60         int v = edge[i].v;
 61         if(!vis[v]) {
 62             dis[v] = dis[u] + 1;
 63             tarjan(v);
 64             fa[v] = u;
 65         }
 66     }
 67     for(int i = Head[u]; ~i; i = Edge[i].next) {
 68         int v = Edge[i].v, k = Edge[i].k;
 69         if(vis[v]) {
 70             int ff = Find(v);
 71             if(k) {
 72                 Edge[i].num = Edge[i^1].num = dis[u] + dis[v] - 2 * dis[ff];
 73                 Edge[i].lca = Edge[i^1].lca = ff;
 74             }
 75             else a[u] = v;
 76         }
 77     }
 78 }
 79 
 80 int doit(int u, int v, int k, int num, int lca)
 81 {
 82     vec.clear();
 83     while(u != lca) {
 84         vec.push_back(a[u]); u = fa[u];
 85     }
 86     while(v != lca) {
 87         vec.push_back(a[v]); v = fa[v];
 88     }
 89     vec.push_back(a[lca]);
 90     sort(vec.begin(), vec.end());
 91     num++;
 92     return vec[num-k];
 93 }
 94 
 95 void solve()
 96 {
 97     for(int i = 0; i < Tot; i += 2) {
 98         int u = Edge[i].u, v = Edge[i].v, k = Edge[i].k, num = Edge[i].num, lca = Edge[i].lca;
 99         if(k) {
100             if(num + 1 < k) puts("invalid request!");
101             else printf("%d
", doit(u, v, k, num, lca));
102         }
103     }
104 }
105 
106 int main()
107 {
108     scanf("%d%d", &n, &m);
109     init();
110     for(int i = 1; i <= n; i++) scanf("%d", a+i);
111     for(int i = 1; i < n; i++) {
112         int u, v;
113         scanf("%d%d", &u, &v);
114         add(u, v); add(v, u);
115     }
116     for(int i = 0; i < m; i++) {
117         int u, v, k;
118         scanf("%d%d%d", &k, &u, &v);
119         Add(u, v, k); Add(v, u, k);
120     }
121     dis[1] = 0;
122     tarjan(1);
123     solve();
124     return 0;
125 }
原文地址:https://www.cnblogs.com/fightfordream/p/5929307.html