luogu P1967 货车运输 最大生成树 倍增LCA

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <cmath>
  5 using namespace std;
  6 struct edg
  7 {
  8     int x,y,w;
  9     friend bool operator < (edg x,edg y)
 10     {
 11         return x.w > y.w;
 12     }
 13 } vec[110000];
 14 const int inf = 999999999;
 15 int n,m,q,cnt,l;
 16 int head[20010],nxt[150000],to[150000],val[150000];
 17 int p[20010][32],fa[100000],size[100000];
 18 int minn[20010][32],deep[20010];
 19 bool vis[20010];
 20 void add(int x,int y,int w)
 21 {
 22     cnt++;
 23     nxt[cnt] = head[x];
 24     head[x] = cnt;
 25     to[cnt] = y;
 26     val[cnt] = w;
 27 }
 28 int getfa(int x)
 29 {
 30     if (fa[x] == x)
 31         return x;
 32     return fa[x] = getfa(fa[x]);
 33 }
 34 void merge(int x,int y)
 35 {
 36     int s1 = getfa(x),s2 = getfa(y);
 37     if (s1 == s2)
 38         return;
 39     if (size[s1] < size[s2])
 40     {
 41         fa[s1] = s2;
 42         size[s2] += size[s1];
 43     }else
 44     {
 45         fa[s2] = s1;
 46         size[s1] += size[s2];
 47     }
 48 }
 49 void dfs(int x)
 50 {
 51     vis[x] = true;
 52     for (int tp = head[x];tp;tp = nxt[tp])
 53     {
 54         if (vis[to[tp]])
 55             continue;
 56         deep[to[tp]] = deep[x] + 1;
 57         p[to[tp]][0] = x;
 58         minn[to[tp]][0] = val[tp];
 59         dfs(to[tp]);
 60     }
 61 }
 62 void init()
 63 {
 64     for (int i = 1;i <= n;i++)
 65         if (!vis[i])
 66         {
 67             p[i][0] = 0;
 68             deep[i] = 1;
 69             dfs(i);
 70         }
 71     l = log2(n);
 72     for (int i = 1;i <= l;i++)
 73         for (int j = 1;j <= n;j++)
 74         {
 75             p[j][i] = p[p[j][i - 1]][i - 1];
 76             minn[j][i] = min(minn[j][i - 1],minn[p[j][i - 1]][i - 1]);
 77         }
 78 }
 79 int lca(int a,int b)
 80 {
 81     int ans = inf;
 82     if (deep[a] < deep[b])
 83         swap(a,b);
 84     for (int j = l;j >= 0;j--)
 85         if (deep[p[a][j]] >= deep[b])
 86         {
 87             ans = min(ans,minn[a][j]);
 88             a = p[a][j];
 89
 90         }
 91     if (a == b)
 92         return ans;
 93     for (int j = l;j >= 0;j--)
 94     {
 95         if (p[a][j] != p[b][j])
 96         {
 97             ans = min(ans, min(minn[a][j], minn[b][j]));
 98             a = p[a][j];
 99             b = p[b][j];
100         }
101     }
102     if (p[a][0] != p[b][0] || p[a][0] == 0)
103         return -1;
104     ans = min(ans,min(minn[a][0],minn[b][0]));
105     return ans;
106 }
107 int main()
108 {
109     scanf("%d%d",&n,&m);
110     for (int i = 1;i <= m;i++)
111         scanf("%d%d%d",&vec[i].x,&vec[i].y,&vec[i].w);
112     for (int i = 1;i <= n;i++)
113     {
114         fa[i] = i;
115         size[i] = 1;
116     }
117     sort(vec + 1,vec + m + 1);
118     for (int i = 1;i <= m;i++)
119         if (getfa(vec[i].x) != getfa(vec[i].y))
120         {
121             add(vec[i].x,vec[i].y,vec[i].w);
122             add(vec[i].y,vec[i].x,vec[i].w);
123             merge(vec[i].x,vec[i].y);
124         }
125     init();
126     scanf("%d",&q);
127     int ta,tb;
128     for (int i = 1;i <= q;i++)
129     {
130         scanf("%d%d",&ta,&tb);
131         printf("%d\n",lca(ta,tb));
132     }
133     return 0;
134 }

原文地址:https://www.cnblogs.com/iat14/p/11519556.html

时间: 2024-10-11 20:49:40

luogu P1967 货车运输 最大生成树 倍增LCA的相关文章

$Noip2013/Luogu1967$ 货车运输 最大生成树+倍增$lca$

$Luogu$ $Sol$ 首先当然是构建一棵最大生成树,然后对于一辆货车的起点和终点倍增跑$lca$更新答案就好.记得预处理倍增的时候不仅要处理走了$2^i$步后是那个点,还有这中间经过的路径权值的最小值以便之后统计答案. 再一看发现这题并没说给的图是联通的,也就是说跑了最大生成树之后可能有若干棵树.所以构树的时候要注意不能随便选一个点构完就不管了,要对每一个联通块都构一次.其他的地方似乎没有因为它有多棵树而有什么不同,只是询问的时候看下是不是一个联通块里的就好. $Code$ #includ

poj1330|bzoj3732|noip2013 货车运输 kruskal+倍增lca

学了一早上倍增,感觉lca还是tarjan好写. poj1330 1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #include <algorithm> 5 #define DEG 20//2^20 6 #define maxn 10010 7 using namespace std; 8 struct node 9 { 10 int v, next; 11 }a[maxn*2

Luogu P1967 货车运输

qwq 这题是知道了正解做法才写的.. 求每两点间最小权值最大的路径,本来我以为要每个点都跑一遍dij(?),后来意识到生成树好像是用来找这个的( ′▽`) 然后我问dtxdalao对不对,他说"我记得这道题好像要用倍增"(我:???剧透会被关进小黑屋的) 其实就是最大生成树是随便建的,然后对于每两点,用倍增求他们的lca,沿途更新最小的边权即为答案 其实我也没怎么debug (i--这种问题就不说了吧) 这题思路还算比较清晰,明白做法之后就分别把几个算法写出来就行了, 注意:lca中

P1967 货车运输

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

【Luogu】P1967货车运输(最大生成森林+倍增LCA)

题目链接 倍增LCA是个什么蛇皮原理啊,循环完了还得再往上跳一次才能到最近公共祖先 合着我昨天WA两次就是因为这个 建最大生成森林,因为图不一定是联通的,所以不一定是一棵树.这个地方用克鲁斯卡尔就好了 然后给这个森林跑一遍DFS,顺便倍增 然后对于每个询问跑LCA,倍增的时候已经顺便求出了最小边权,所以往上跳的同时更新答案. 代码如下 #include<cstdio> #include<cctype> #include<cstdlib> #include<cmat

洛谷T1967 货车运输 Kruskal最大生成树&amp;&amp;倍增LCA

这题的题意是:对于每组x.y,求x到y路径上最小边权的最大值.于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大.有了树之后,要求路径,那就要考虑LCA.首先,这题可以树剖,但是我太懒了,于是写了倍增233具体搞法:Kruskal跑出最大生成树,然后在树上倍增LCA,处理出2个数组:fa[][]和minv[][]:fa[][]表示第2^k个父亲是谁,minv[][]表示当前节点到其第2^k个父亲的路径上的最小边权.对于每次查询,在求LCA的同时,

[luogu 1967]货车运输

货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条

洛谷 P1967 货车运输 Label: 倍增LCA &amp;&amp; 最小瓶颈路

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

luogu 1967 货车运输(最大瓶颈生成树+LCA)

题意:给出一颗n个点的图,q个询问,每次询问u到v的路径中最小的边最大是多少. 图的最大瓶颈生成树有一个性质,对于该图的任意两个点,在树中他们之间路径的最小边最大. 由于这个图不一定联通,于是我们对它的联通块都求一次最大瓶颈生成树. 每次询问就变成了在最大瓶颈生成树上找出u到v路径的最小边. 这个显然可以用LCA维护点到它的2^x祖先之间的边的最小值来解决. # include <cstdio> # include <cstring> # include <cstdlib&g