[HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

这题以前做过…现在用tarjan搞一发…竟然比以前暴力过的慢…………

由于是离线算法,需要Query来保存查询数据,Ans来保存结果。最后输出的时候按照idx的顺序输出,所以胡搞了个排序。。

dfs每次更新depth,当前点depth是上一个点累积下来的。

  1 /*
  2 ━━━━━┒ギリギリ♂ eye!
  3 ┓┏┓┏┓┃キリキリ♂ mind!
  4 ┛┗┛┗┛┃\○/
  5 ┓┏┓┏┓┃ /
  6 ┛┗┛┗┛┃ノ)
  7 ┓┏┓┏┓┃
  8 ┛┗┛┗┛┃
  9 ┓┏┓┏┓┃
 10 ┛┗┛┗┛┃
 11 ┓┏┓┏┓┃
 12 ┛┗┛┗┛┃
 13 ┓┏┓┏┓┃
 14 ┃┃┃┃┃┃
 15 ┻┻┻┻┻┻
 16 */
 17 #include <algorithm>
 18 #include <iostream>
 19 #include <iomanip>
 20 #include <cstring>
 21 #include <climits>
 22 #include <complex>
 23 #include <fstream>
 24 #include <cassert>
 25 #include <cstdio>
 26 #include <bitset>
 27 #include <vector>
 28 #include <deque>
 29 #include <queue>
 30 #include <stack>
 31 #include <ctime>
 32 #include <set>
 33 #include <map>
 34 #include <cmath>
 35
 36 using namespace std;
 37
 38 #define fr first
 39 #define sc second
 40 #define cl clear
 41 #define BUG puts("here!!!")
 42 #define W(a) while(a--)
 43 #define pb(a) push_back(a)
 44 #define Rint(a) scanf("%d", &a)
 45 #define Rll(a) scanf("%lld", &a)
 46 #define Rs(a) scanf("%s", a)
 47 #define Cin(a) cin >> a
 48 #define FRead() freopen("in", "r", stdin)
 49 #define FWrite() freopen("out", "w", stdout)
 50 #define Rep(i, len) for(int i = 0; i < (len); i++)
 51 #define For(i, a, len) for(int i = (a); i < (len); i++)
 52 #define Cls(a) memset((a), 0, sizeof(a))
 53 #define Clr(a, x) memset((a), (x), sizeof(a))
 54 #define Full(a) memset((a), 0x7f7f, sizeof(a))
 55 #define lrt rt << 1
 56 #define rrt rt << 1 | 1
 57 #define pi 3.14159265359
 58 #define RT return
 59 typedef long long LL;
 60 typedef long double LD;
 61 typedef unsigned long long ULL;
 62 typedef pair<int, int> pii;
 63 typedef pair<string, int> psi;
 64 typedef map<string, int> msi;
 65 typedef vector<LL> vl;
 66 typedef vector<vl> vvl;
 67 typedef vector<bool> vb;
 68
 69 typedef struct Query {
 70     int idx;
 71     int u, v;
 72     Query() {}
 73     Query(int uu, int vv, int ii) : u(uu), v(vv), idx(ii) {}
 74 }Query;
 75
 76 typedef struct Edge {
 77     int v, w;
 78     Edge() {}
 79     Edge(int vv, int ww) : v(vv), w(ww) {}
 80 }Edge;
 81
 82 typedef struct Ans {
 83     int idx;
 84     int ans;
 85     Ans() {}
 86     Ans(int aa, int ii) :ans(aa), idx(ii) {}
 87 }Ans;
 88
 89 const int maxn = 40010;
 90 const int maxm = 222;
 91 int n, m, qcnt, acnt;
 92 int depth[maxn];
 93 int in[maxn];
 94 bool vis[maxn];
 95 int pre[maxn];
 96 Query q[maxm];
 97 Ans ans[maxn];
 98 vector<Edge> G[maxn];
 99 int u, v, w;
100
101 int find(int x) {
102     return x == pre[x] ? x : pre[x] = find(pre[x]);
103 }
104
105 void unite(int x, int y) {
106     x = find(x);
107     y = find(y);
108     if(x != y) pre[y] = x;
109 }
110
111 void dfs(int u, int d) {
112     // pre[u] = u;
113     depth[u] = d;
114     Rep(i, G[u].size()) {
115         int v = G[u][i].v;
116         if(!vis[v]) {
117             dfs(v, d+G[u][i].w);
118             unite(u, v);
119         }
120     }
121     vis[u] = 1;
122     Rep(i, qcnt) {
123         int uu = q[i].u;
124         int vv = q[i].v;
125         int idx = q[i].idx;
126         if(vis[uu] && vv == u) {
127             ans[acnt].idx = idx;
128             ans[acnt++].ans = abs(depth[vv] - depth[uu]);
129         }
130         if(vis[vv] && uu == u) {
131             ans[acnt].idx = idx;
132             ans[acnt++].ans = abs(depth[uu] - depth[vv]);
133         }
134     }
135 }
136
137 bool cmp(Ans x, Ans y) {
138     return x.idx < y.idx;
139 }
140
141 int main() {
142     // FRead();
143     int T;
144     Rint(T);
145     W(T) {
146         Rint(n); Rint(m);
147         Cls(vis); Cls(depth); Cls(ans); Cls(G);
148         acnt = qcnt = 0; Rep(i, n+5) G[i].cl(), pre[i] = i;
149         Rep(i, n-1) {
150             Rint(u); Rint(v); Rint(w);
151             G[u].push_back(Edge(v, w));
152             in[v]++;
153         }
154         Rep(i, m) {
155             Rint(u); Rint(v);
156             q[qcnt++] = Query(u, v, i);
157         }
158         For(i, 1, n+1) if(in[i] == 0) dfs(i, 0);
159         sort(ans, ans+acnt, cmp);
160         Rep(i, acnt) {
161             printf("%d\n", ans[i].ans);
162         }
163     }
164     RT 0;
165 }
时间: 2024-12-20 22:38:12

[HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)的相关文章

POJ 1330 LCA最近公共祖先 离线tarjan算法

题意要求一棵树上,两个点的最近公共祖先 即LCA 现学了一下LCA-Tarjan算法,还挺好理解的,这是个离线的算法,先把询问存贮起来,在一遍dfs过程中,找到了对应的询问点,即可输出 原理用了并查集和dfs染色,先dfs到底层开始往上回溯,边并查集合并 一边染色,这样只要询问的两个点均被染色了,就可以输出当前并查集的最高父亲一定是LCA,因为我是从底层层层往上DSU和染色的,要么没被染色,被染色之后,肯定就是当前节点是最近的 #include <iostream> #include <

HDU2874 Connections between cities 最近公共祖先+离线

给了你n个村庄把,然后m条路径,q个询问,问你两个点之间的最短距离 分析:由于按照题意来说本图是没有环的,所以求a,b的最近公共祖先 到他们的各自的距离之和就是 那个他们的最短路啦,用的是tarjan来做的,我的方法定义了一个dis数组来随时记录路径的长度,其它大神各有自己的神奇之法 #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstri

hicocoder1067 最近公共祖先&#183;二(tarjan算法)

tarjan算法是处理最近公共祖先问题的一种离线算法. 算法思路: 先将所有的询问搜集起来. 然后对树进行dfs,在dfs的过程中对节点进行着色.当到达某个节点x的时候,给x着色为灰色,离开x的时候,着色为黑色. 当到达x并将其着色为灰色后,处理与x相关联的所有询问: (这里有一个显然的事实:所有的灰色节点都是x的祖先) (1)若询问的另一个节点y是灰色,那么该询问的结果为y: (2)若询问的另一个节点y是黑色,那么询问结果应为离y最近的y的灰色祖先(因为所有灰色节点都是x的祖先,所以离y最近的

最近公共祖先LCA(Tarjan算法)的思考和算法实现——转载自Vendetta Blogs

最近公共祖先LCA(Tarjan算法)的思考和算法实现 LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了flase...看的时候注意一下! //还有...这篇字比较多 比较杂....毕竟是第一次嘛 将就将就 后面会重新改!!! 首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖先节点,而最近公共祖先

【bzoj4551】[Tjoi2016&amp;Heoi2016]树 离线处理+并查集

题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记.)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先)你能帮帮他吗? 输入 输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v有一条有向边接下来Q行,形如"oper

URAL1671 Anansi&#39;s Cobweb(离线做 + 并查集)

传送门 大意:给出一个无向图,删除Q条边,每删除一次就询问一次目前的连通块的数目. 思路:离线搞, 把删边转换为加边,每加一次边,若两个顶点不连通就用并查集把着这两个连通块合并. 代码: #include<cstdio> #include<cstring> #include<algorithm> #define MAXN 100005 using namespace std; int n, m, q; int s[MAXN], t[MAXN]; int ban[MAXN

【bzoj5183】[Baltic2016]Park 离线+对偶图+并查集

题目描述 在Byteland的首都,有一个矩形围栏围起来的公园.在这个公园里树和访客都以一个圆形表示.公园有四个出入口,每个角落一个(1=左下角,2=右下角,3=右上角,4=左上角).访客能通过这些出入口进出公园.访客在同时碰到一个角落的两条边时就可以通过该角落进出公园.访客在公园里可以自由地移动,但他们不能和树和围栏相交.对于每个访客,给定他们进入公园的出入口,你的任务是计算他们能在哪个出入口离开公园. 输入 输入的第一行包含两个整数:n,m:树的数量和访客的数量. 第二行包含两个整数:w,h

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11320    Accepted Submission(s): 4119 Problem Description There are n houses in the village and some bidirectional roads c

[图论] LCA(最近公共祖先)Tarjan 离线算法

很好的参考资料:http://taop.marchtea.com/04.04.html    下面的配图和部分文字转载于此文章 离线算法就是指统一输入后再统一输出,而不是边输入边实时输出.Tarjan算法的复杂度为O(N+Q),Q为询问的次数. 由于是离线算法,所以要保存输入的信息,次序问题. 若两个结点u.v分别分布于某节点t 的左右子树,那么此节点 t即为u和v的最近公共祖先.更进一步,考虑到一个节点自己就是LCA的情况,得知: ?若某结点t 是两结点u.v的祖先之一,且这两结点并不分布于该