HDU 2586 How far away ? (离线LCA Tarjan算法模板) - Tc_To_Top的专栏 - 博客频道 - CSDN.NET
Problem Description
Tarjan
http://www.cppblog.com/CodeStream/archive/2011/03/24/142651.aspx
http://blog.csdn.net/tc_to_top/article/details/43941007
DFS
题目的意思就是给定一些houses的编号,及这些编号房子之间的距离,然后有m次询问,每次询问给出两个房子的编号,要求给出这两个房子的最小距离。这张图是树图,也就是总共N个点N-1条边,然后能把所有点全部连通。本身分析题目很容易知道本题就是求最小公共祖先的问题,首先确定一个根节点,然后DFS遍历一遍计算此根节点到所有节点的距离,然后可以用离线的tarjan算法,来找到两个询问节点a和b的最近公共祖先c,然后要求的结果就是dist[a] - dist[c] + dist[b] - dist[c],意思很好理解,画棵树看看就可以了,而且这种思路也是很容易想到的。这里用了一下非递归的DFS直接来求,每次询问直接使用DFS求亮点之间的距离
http://blog.csdn.net/iaccepted/article/details/43072689
http://blog.csdn.net/hnust_xiehonghao/article/details/9071803
LCA。RMQ 的在线算法,任何一个根为起点都可以,dfs 的时候顺便用 dis 记录到根的距离,求出 a 和 b 的 LCA c,则距离等于 dis [ a ] + dis [ b ] - 2 X dis [ c ]。因为 RMQ 数组的长度开小了,所以 WA 了很多遍。
Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Tarjan
http://www.cppblog.com/CodeStream/archive/2011/03/24/142651.aspx
http://blog.csdn.net/tc_to_top/article/details/43941007
DFS
题目的意思就是给定一些houses的编号,及这些编号房子之间的距离,然后有m次询问,每次询问给出两个房子的编号,要求给出这两个房子的最小距离。这张图是树图,也就是总共N个点N-1条边,然后能把所有点全部连通。本身分析题目很容易知道本题就是求最小公共祖先的问题,首先确定一个根节点,然后DFS遍历一遍计算此根节点到所有节点的距离,然后可以用离线的tarjan算法,来找到两个询问节点a和b的最近公共祖先c,然后要求的结果就是dist[a] - dist[c] + dist[b] - dist[c],意思很好理解,画棵树看看就可以了,而且这种思路也是很容易想到的。这里用了一下非递归的DFS直接来求,每次询问直接使用DFS求亮点之间的距离
http://blog.csdn.net/iaccepted/article/details/43072689
http://blog.csdn.net/hnust_xiehonghao/article/details/9071803
- struct haha
- {
- int pos;
- int val;
- }temp,q;
- vector<struct haha>a[44444];
- int n,m,flag,e,vis[444444];
- void DFS(int s,int ans)
- {
- //printf("s=%d\n",s);
- int size,i;
- if(vis[s]) return ;
- if(flag) return ;
- if(s==e) {printf("%d\n",ans);flag=1;return;}
- if(a[s].empty()) return ;
- else
- {
- vis[s]=1;
- size=a[s].size();
- for(i=0;i<size;i++)
- DFS(a[s][i].pos,ans+a[s][i].val);
- vis[s]=0;
- }
- }
- int main()
- {
- int cas;
- scanf("%d",&cas);
- while(cas--)
- {
- int i,j,x,y,z;
- scanf("%d %d",&n,&m);
- for(i=0;i<n-1;i++)
- {
- scanf("%d %d %d",&x,&y,&z);
- q.pos=y;q.val=z;
- a[x].push_back(q);
- q.pos=x;q.val=z;
- a[y].push_back(q);
- }
- for(j=0;j<m;j++)
- {
- memset(vis,0,sizeof(vis));
- flag=0;
- int s;
- scanf("%d %d",&s,&e);
- DFS(s,0);
- }
- for(i=0;i<n;i++)
- {
- a[i].clear();
- }
- }
- return 0;
- }
LCA。RMQ 的在线算法,任何一个根为起点都可以,dfs 的时候顺便用 dis 记录到根的距离,求出 a 和 b 的 LCA c,则距离等于 dis [ a ] + dis [ b ] - 2 X dis [ c ]。因为 RMQ 数组的长度开小了,所以 WA 了很多遍。
- int n, ind;
- int next[EMAX], fir[VMAX], w[EMAX], v[EMAX];
- int k;
- int dis[VMAX], vs[VMAX * 5], dep[VMAX * 5], id[VMAX];
- bool vis[VMAX];
- int dp[VMAX * 5][25];
- void init () {
- ind = k = 0;
- memset(fir, -1, sizeof(fir));
- memset(vis, 0, sizeof(vis));
- }
- void add_edge (int f, int t, int val) {
- v[ind] = t;
- w[ind] = val;
- next[ind] = fir[f];
- fir[f] = ind;
- ++ind;
- }
- void dfs (int x, int d) {
- id[x] = k;
- vs[k] = x;
- dep[k++] = d;
- vis[x] = 1;
- for (int e = fir[x]; e != -1; e = next[e]) {
- int V = v[e];
- if (!vis[V]) {
- dis[V] = dis[x] + w[e];
- dfs(V, d + 1);
- vs[k] = x;
- dep[k++] = d;
- }
- }
- }
- void RMQ_init () {
- for (int i = 0; i < k; ++i) dp[i][0] = i;
- for (int j = 1; (1 << j) <= k; ++j) {
- for (int i = 0; i + (1 << j) - 1 < k; ++i) {
- int a = dp[i][j - 1];
- int b = dp[i + (1 << (j - 1))][j - 1];
- if (dep[a] > dep[b]) dp[i][j] = b;
- else dp[i][j] = a;
- }
- }
- }
- int RMQ (int L, int R) {
- int len = 0;
- while ((1 << (len + 1)) <= (R - L + 1)) ++len;
- int a = dp[L][len];
- int b = dp[R - (1 << len) + 1][len];
- if (dep[a] > dep[b]) return b;
- return a;
- }
- int LCA (int a, int b) {
- int L = min(id[a], id[b]);
- int R = max(id[a], id[b]);
- int Min = RMQ(L, R);
- return vs[Min];
- }
- int main () {
- int T;
- scanf("%d", &T);
- while (T--) {
- init();
- int m;
- scanf("%d%d", &n, &m);
- for (int i = 1; i <= n - 1; ++i) {
- int a, b, val;
- scanf("%d%d%d", &a, &b, &val);
- add_edge(a, b, val);
- add_edge(b, a, val);
- }
- dfs (1, 1);
- RMQ_init();
- while (m--) {
- int a, b;
- scanf("%d%d", &a, &b);
- int node = LCA(a, b);
- printf("%d\n", dis[a] + dis[b] - 2 * dis[node]);
- }
- }
- return 0;
- }