图论——公共祖先

Wikioi 3287 货车运输

题目描述 Description

A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入描述 Input Description

第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

输出描述 Output Description

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

样例输入 Sample Input

4 3 
1 2 4 
2 3 3 
3 1 1 
3
1 3 
1 4 
1 3

样例输出 Sample Output

3
-1
3

数据范围及提示 Data Size & Hint

对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000; 
对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000; 
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

思路:

lca模板题

代码:

  1 include<iostream>
  2 #include<cstdio>
  3 #include<string>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<vector>
  7 #define mx 50050
  8 #define maxint 100000000
  9 #define mp 30
 10 using namespace std;
 11 struct Edge{
 12     int v;
 13     int w;
 14 };
 15 struct Edget{
 16     int u;
 17     int v;
 18     int w;
 19 };
 20 int n,m,q,pre[mx],pos = 0,f[mx][mp],deep[mx];
 21 vector<Edge> edge[mx];
 22 Edget edget[mx];
 23 bool cmp(Edget a,Edget b){
 24     return a.w > b.w;
 25 }
 26 int find(int x)
 27 {
 28     int r=x;
 29     while ( pre[r ] != r )
 30           r=pre[r ];
 31
 32     int i=x , j ;
 33     while( i != r )
 34     {
 35          j = pre[ i ];
 36          pre[ i ]= r ;
 37          i=j;
 38     }
 39     return r ;
 40 }
 41
 42
 43 void join(int x,int y)
 44
 45 {
 46     int fx=find(x),fy=find(y);
 47     if(fx!=fy)
 48         pre[fx ]=fy;
 49 }
 50 void dfs(int x)
 51 {
 52     int y,j,k;
 53     vector<Edge>::iterator it;
 54     y=f[x][0];
 55     deep[x]=deep[y]+1;
 56     for (k=0;f[y][k]!=0;k++) {   f[x][k+1]=f[y][k];    y=f[y][k];    }
 57     for (it=edge[x].begin();it!=edge[x].end();it++) if ((it->v) != f[x][0])
 58     {
 59         f[it->v][0]=x;     dfs(it->v);
 60     }
 61 }
 62 int findlca(int x,int y)
 63 {
 64     int z,k,dd;
 65     if (deep[x]<deep[y]) {z=x; x=y; y=z;}
 66     k=0;
 67     for (dd=deep[x]-deep[y];dd!=0;dd=dd>>1)
 68     {    if (dd&1) x=f[x][k];     k++;    }
 69     if (x==y) return x;
 70     k=0;
 71     while (k>=0)
 72         if (f[x][k]!=f[y][k]) {x=f[x][k];y=f[y][k]; k++;}
 73         else k--;
 74     return f[x][0];
 75 }
 76
 77 void output(){
 78     cout<<"pos : "<<pos<<endl;
 79     for(int i = 0;i < pos;i++){
 80         cout<<edget[i].u<<" "<<edget[i].v<<" "<<edget[i].w<<endl;
 81     }
 82     vector<Edge>::iterator it;
 83     for(int i = 1;i <= n;i++){
 84         cout<<i<<" :"<<endl;
 85         for(it = edge[i].begin();it != edge[i].end();it++){
 86             cout<<"("<<it->v<<" , "<<it->w<<")"<<endl;
 87         }
 88     }
 89 }
 90 void input(){
 91     cin>>n>>m;
 92     int x,y,z;
 93     for(int i = 1;i <= m;i++){
 94         cin>>x>>y>>z;
 95         edget[pos].w = z;
 96         edget[pos].v = y;
 97         edget[pos].u = x;
 98         pos++;
 99
100     }
101 }
102 void instruct(){
103     sort(edget,edget+pos,cmp);
104     Edge tmp;
105     for(int i = 1;i <= n;i++) pre[i] = i;
106     for(int i = 0;i < pos;i++){
107         if(find(edget[i].u) != find(edget[i].v)){
108             join(edget[i].u,edget[i].v);
109             tmp.v = edget[i].v;
110             tmp.w = edget[i].w;
111             edge[edget[i].u].push_back(tmp);
112             tmp.v = edget[i].u;
113             edge[edget[i].v].push_back(tmp);
114         }
115     }
116     for(int i = 1;i <= n;i++) dfs(i);
117
118 }
119 void lca(){
120     cin>>q;
121     int x,y,r,ans;
122     vector<Edge>::iterator it;
123     for(int i = 1;i <= q;i++){
124         ans = maxint;
125         cin>>x>>y;
126         if(find(x) != find(y)){
127             cout<<-1<<endl;
128             continue;
129         }
130         r = findlca(x,y);
131         for(int i = x;i != r;i = f[i][0]){
132             for(it=edge[i].begin();it!=edge[i].end();it++){
133                 if(it->v == f[i][0]) ans = min(it->w,ans);
134             }
135         }
136         for(int i = y;i != r;i = f[i][0]){
137             for(it=edge[i].begin();it!=edge[i].end();it++){
138                 if(it->v == f[i][0]) ans = min(it->w,ans);
139             }
140         }
141         cout<<ans<<endl;
142     }
143
144 }
145 int main(){
146     input();
147     instruct();
148     lca();
149     return 0;
150 } 

时间: 2024-08-05 11:16:35

图论——公共祖先的相关文章

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

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

图论-最近公共祖先-在线树上倍增

有关概念: 最近公共祖先(LCA,Lowest Common Ancestors):对于有根树T的两个结点u.v,最近公共祖先表示u和v的深度最大的共同祖先. 树上倍增是求LCA的在线算法(对于每一个询问输入后即计算) 思路: fa[i][j]表示编号为j的结点从下往上的第2i个祖先 即fa[0][j]表示j的父结点,递推式为fa[i][j]=fa[i-1][fa[i-1][j]],即j的第2i个祖先为j的第2i-1个祖先的第2i-1个祖先 另:不存在第2i个祖先(即2i超过j的深度)时,f[i

『图论』LCA最近公共祖先

概述篇 LCA(Least Common Ancestors),即最近公共祖先,是指这样的一个问题:在一棵有根树中,找出某两个节点 u 和 v 最近的公共祖先. LCA可分为在线算法与离线算法 在线算法:指程序可以以序列化的方式一个一个处理输入,也就是说在一开始并不需要知道所有的输入. 离线算法:指一开始就需要知道问题的所有输入数据,而在解决一个问题后立即输出结果. 算法篇 对于该问题,很容易想到的做法是从 u.v 分别回溯到根节点,然后这两条路径中的第一个交点即为 u.v 的最近公共祖先,在一

Solution: 最近公共祖先&#183;一 [hiho一下 第十三周]

题目1 : 最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢? “为什么呢?”小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边. “嘿嘿,小Hi,你快过来看!”小Ho招呼道. “你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来……什么!我们居然有同一个

POJ1330 Nearest Common Ancestors【最近公共祖先】【Tarjan-LCA算法】

Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 19636Accepted: 10412 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each node

【洛谷P3379】【模板】最近公共祖先(LCA)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5

50、树中两个节点的公共祖先

详细的询问: 1.该树是二叉查找树? 最近公共祖先----二叉查找树:(http://www.lintcode.com/problem/lowest-common-ancestor/) 思路:利用左子树特点:左子树 < 根 <= 右,输入节点跟根节点比较,都小于,在左子树,都大约右子树,递归的去遍历:找到当前节点在两个输入大小之间,当前节点就是. 递归和非递归 public class Solution { public TreeNode lowestCommonAncestor(TreeNo

[最近公共祖先] POJ 3728 The merchant

The merchant Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 4556   Accepted: 1576 Description There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and w

lca最近公共祖先(st表)

大体思路 1.求出每个元素在树中的深度 2.用st表预处理的方法处理出f[i][j],f[i][j]表示元素i上方第2^j行对应的祖先是谁 3.将较深的点向上挪,直到两结点的深度相同 4.深度相同后,祖先可能就在上方,再走几步就到了,于是两个点同时向上移 具体的方法和代码贴在下面 ↓ 具体来看 1.求出每个元素在树中的深度 //求每个节点在树中的深度 void dfs(int pos,int pre)//pre是pos的父节点 { for(int i=0;i<v[pos].size;i++)//