BZOJ 3732 Network Kruskal重构树

题目大意:给定一个n个点m条边的无向连通图,k次询问两点之间所有路径中最长边的最小值

Kruskal+倍增LCA做法见http://blog.csdn.net/popoqqq/article/details/39755703

LCT做法见http://blog.csdn.net/popoqqq/article/details/39929277

Kruskal重构树真是强大……一不小心手滑就RANK1啥的……

每加入一条边时,我们并不链接这条边的两端点,而是把这条边两端点所在并查集的根连接起来,而且是按秩合并

这样做的好处就是任何一个节点到根的路径长度不超过logn

且由于Kruskal重构树的性质,两点之间的最长边和原图相同,且最长边的一端连接的一定是两点的LCA

于是直接暴力向上找就行 如果加上倍增的话或许能优化到O(loglogn)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 15100
using namespace std;
struct abcd{
    int x,y,f;
    bool operator < (const abcd &Y) const
    {
        return f < Y.f ;
    }
}edges[M<<1];
int n,m,k;
int belong[M],fa[M],size[M],dis[M],dpt[M];
int Find(int x)
{
    if(!belong[x])
        belong[x]=x,size[x]=1;
    if(belong[x]==x)
        return x;
    return belong[x]=Find(belong[x]);
}
int Get_Depth(int x)
{
    if(dpt[x]) return dpt[x];
    if(!fa[x]) return dpt[x]=1;
    return dpt[x]=Get_Depth(fa[x])+1;
}
void Kruskal()
{
    int i;
    sort(edges+1,edges+m+1);
    for(i=1;i<=m;i++)
    {
        int x=Find(edges[i].x);
        int y=Find(edges[i].y);
        if(x==y) continue ;
        if(size[x]>size[y])
            swap(x,y);
        belong[x]=y;
        size[y]=max(size[y],size[x]+1);
        fa[x]=y;
        dis[x]=edges[i].f;
    }
}
int Query(int x,int y)
{
    int re=0;
    if(dpt[x]<dpt[y])
        swap(x,y);
    while(dpt[x]>dpt[y])
        re=max(re,dis[x]),x=fa[x];
    while(x!=y)
        re=max(re,dis[x]),re=max(re,dis[y]),x=fa[x],y=fa[y];
    return re;
}
int main()
{
    int i,x,y;
    cin>>n>>m>>k;
    for(i=1;i<=m;i++)
        scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f);
    Kruskal();
    for(i=1;i<=n;i++)
        Get_Depth(i);
    for(i=1;i<=k;i++)
    {
        scanf("%d%d",&x,&y);
        printf("%d\n", Query(x,y) );
    }
}
时间: 2024-10-10 17:30:30

BZOJ 3732 Network Kruskal重构树的相关文章

【BZOJ 3732】 Network Kruskal重构树+倍增LCA

Kruskal重构树裸题, Sunshine互测的A题就是Kruskal重构树,我通过互测了解到了这个神奇的东西... 理解起来应该没什么难度吧,但是我的Peaks连WA,,, 省选估计要滚粗了TwT #include<cstdio> #include<cstring> #include<algorithm> #define for1(i,a,n) for(int i=(a);i<=(n);i++) #define for2(i,a,n) for(int i=(a

BZOJ 3732 Network Kruskal+倍增LCA

题目大意:给定一个n个点m条边的无向连通图,k次询问两点之间所有路径中最长边的最小值 NOIP2013 货车运输,几乎就是原题...只不过最小边最大改成了最大边最小... 首先看到最大值最小第一反应二分答案 但是二分答案O(kmlogn)明显做不了 这里我们考虑最小生成树 先生成一棵最小生成树,然后每次询问利用倍增LCA求出路径上的最大权值即可 本蒟蒻居然把LCA写挂了... 而且样例还过了... 伤不起啊... 90%达成 剩下一道刷点啥呢... #include<cstdio> #incl

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

BZOJ 3551 ONTAK2010 Peaks加强版 Kruskal重构树+可持久化线段树

题目大意:同3545 强制在线 3545题解传送门:http://blog.csdn.net/popoqqq/article/details/40660953 强制在线没法排序 启发式合并也就用不了了 Kruskal重构树是个挺好玩的东西 可以拿来处理一些最小生成树的边权最值问题 这里我们Kruskal连边时并不直接连边 而是新建一个节点ext 将两个点所在子树都连到ext的儿子上 比如说样例的树就建成了这样 图中红色的是原图的边权,黑色的是原图上的点 这样生成的树有一些十分优美的性质: 1.二

Kruskal重构树

不支持时间旅行的可持久化并查集 给定 n 个点, 以及 m 次操作, 操作有两种: ① 将点 x 与点 y 进行连边; ② 询问在前 t 次操作操作中, x 与 y 是否连通. n <= 100000, 强制在线. 核心模型 n 个点, m 条带权边的无向图. 多次询问点 x 和点 y 在边权不超过 w 的边的作用下的连通性信息(例如, 是否连通). 强制在线. 对于不支持时间旅行的并查集问题, 将时间这一维给量化之后, 可以等价地看成这个核心模型. 对于操作①, 我们相当于连边 (x, y)

算法学习——kruskal重构树

kruskal重构树是一个比较冷门的数据结构. 其实可以看做一种最小生成树的表现形式. 在普通的kruskal中,如果一条边连接了在2个不同集合中的点的话,我们将合并这2个点所在集合. 而在kruskal重构树中,如果一条边连接了在2个不同集合中的点,我们将新建一个节点出来,并用这个新节点作为一个中转连接这2个集合. 如图就是一棵kruskal重构树,方点表示新建出的节点,圆点是原图中的点,方点点权即边权. 这样建出的树会有一些美妙的性质,例如往上走点权是递增的,原图中的每个点都是叶子节点等.

[IOI2018]werewolf狼人——kruskal重构树+可持久化线段树

题目链接: IOI2018werewolf 题目中编号都是从0开始,太不舒服了,我们按编号从1开始讲QAQ. 题目大意就是询问每次从一个点开始走只能走编号在[l,n]中的点,在任意点变成狼,之后只能走[0,r]中的点,是否能到达另一个点. 后一部分其实就是找有哪些点只走[0,r]中的点能到达终点,那么反过来看,就是终点只走[0,r]中的点能到达哪些点. 那么只要起点能到达的点和终点能到达的点中有交集就有解. 因为起点只能走一些编号较大的点,那么我们求出原图的最大生成树,建出kruskal重构树,

[IOI2018] werewolf 狼人 kruskal重构树,主席树

[IOI2018] werewolf 狼人 LG传送门 kruskal重构树好题. 日常安利博客文章 这题需要搞两棵重构树出来,这两棵重构树和我们平时见过的重构树有点不同(据说叫做点权重构树?),根据经过我们简化的建树方法,这两棵树不再是二叉树,但是仍具有kruskal重构树的优秀性质,建议结合后面的描述理解. 看这题需要首先我们从\(S\)走到\(T\)转化为分别从\(S\)和\(T\)出发寻找能共同到达的点,需要快速求出从某个点出发经过点权不大(小)于\(r\)(\(l\))的点,考虑kru

Gym - 101173H Hangar Hurdles (kruskal重构树/最小生成树+LCA)

题目大意:给出一个n*n的矩阵,有一些点是障碍,给出Q组询问,每组询问求两点间能通过的最大正方形宽度. 首先需要求出以每个点(i,j)为中心的最大正方形宽度mxl[i][j],可以用二维前缀和+二分或者BFS求. 然后每相邻的两个点建一条权值为min(mxl[i][j],mxl[i'][j'])的边,求出整个图的最小生成树(注意边权要从大到小排序,实际上求出的是边权的“最大生成树”)或者kruskal重构树,对于每组询问(x1,y1),(x2,y2),答案为最小生成树上两点间路径的最小边权,或者