洛谷.4172.[WC2006]水管局长(LCT Kruskal)

题目链接 洛谷(COGS上也有)
不想去做加强版了。。(其实处理一下矩阵就好了)

题意: 有一张图,求一条x->y的路径,使得路径上最长边尽量短并输出它的长度。会有<=5000次删边。

这实际上就是动态地维护MST。用LCT维护MST,路径询问也能直接查询,每次删边看这条边是否在MST上。
只有1000个点!边直接矩阵存。
而且删边次数很少,于是最初想的是每次删边用堆优化Prim O(nlogn)重新求一遍MST。但是5000100010=5e7。。(也许行吧)
日常删边改成加边,离线即可。加边时MST上的求路径Max,看是否需要Cut,重新Link.(正序的话还要找一遍没被删的连接两集合的最小边)

#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define MAXIN (200000)
const int N=1005,M=1e5+5,S=N+M;//虽然维护的是MST但大小还是要M的。。当然可以记录每条树边并循环利用,以后再写吧。。

int n,m,type[M],ff[N],qx[M],qy[M],id[N][N],Ans[M];
char IN[MAXIN],*SS=IN,*TT=IN;
bool ban[M];
struct Edge{
    int fr,to,val;
    Edge() {}
    Edge(int f,int t,int v):fr(f),to(t),val(v) {}
    bool operator <(const Edge &a)const{
        return val<a.val;
    }
}e[M];
namespace LCT
{
    #define lson son[x][0]
    #define rson son[x][1]

    int pos[S],val[S],son[S][2],fa[S],sk[S];
    bool rev[S];
    inline int Get(int x,int y){
        return val[x]>val[y]?x:y;
    }
    inline void Update(int x){
        pos[x]=Get(x,Get(pos[lson],pos[rson]));//是左右儿子的pos!又一次写错。。
    }
    inline bool n_root(int x){
        return son[fa[x]][0]==x||son[fa[x]][1]==x;
    }
    inline void Rev(int x){
        std::swap(lson,rson), rev[x]^=1;
    }
    void PushDown(int x){
        if(rev[x]) Rev(lson),Rev(rson),rev[x]=0;
    }
    void Rotate(int x)
    {
        int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
        if(n_root(a)) son[b][son[b][1]==a]=x;
        if(son[x][r]) fa[son[x][r]]=a;
        fa[a]=x, fa[x]=b, son[a][l]=son[x][r], son[x][r]=a;
        Update(a);
    }
    void Splay(int x)
    {
        int t=1,a=x; sk[1]=x;
        while(n_root(a)) sk[++t]=a=fa[a];
        while(t) PushDown(sk[t--]);
        while(n_root(x))
        {
            if(n_root(a=fa[x])) Rotate(son[a][1]==x^son[fa[a]][1]==a?x:a);
            Rotate(x);
        }
        Update(x);
    }
    void Access(int x){
        for(int pre=0; x; x=fa[pre=x])
            Splay(x), rson=pre, Update(x);
    }
    void Make_root(int x){
        Access(x), Splay(x), Rev(x);
    }
    void Split(int x,int y){
        Make_root(x), Access(y), Splay(y);
    }
    int Find_root(int x)
    {
        Access(x), Splay(x);
        while(lson) x=lson;
        return x;
    }
    void Link(int x){//在合法的情况下Find_root()并不是必须的(不维护子树信息的话?)
        Make_root(e[x].to), fa[fa[e[x].to]=x+N]=e[x].fr;
        val[x+N]=e[x].val, Update(x+N);
    }
    void Cut(int x){//注意这的编号
        Access(e[x-N].to), Splay(x), lson=rson=fa[lson]=fa[rson]=0;
    }
}
using namespace LCT;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
int Get_fa(int x){
    return x==ff[x]?x:ff[x]=Get_fa(ff[x]);
}

int main()
{
    n=read(),m=read();int Q=read();
    for(int x,y,i=1; i<=m; ++i) x=read(),y=read(),e[i]=Edge(x,y,read());
    std::sort(e+1,e+1+m);//先排序再编号!
    for(int i=1; i<=m; ++i) id[e[i].fr][e[i].to]=id[e[i].to][e[i].fr]=i;
    for(int i=1; i<=Q; ++i)
    {
        type[i]=read(),qx[i]=read(),qy[i]=read();
        if(type[i]==2) ban[id[qx[i]][qy[i]]]=1;
    }
    for(int i=1; i<=n; ++i) ff[i]=i;
    for(int t,x,y,k=0,i=1; i<=m; ++i)
        if(!ban[t=id[x=e[i].fr][y=e[i].to]] && Get_fa(x)!=Get_fa(y))
        {//不需要记r1,r2
            ff[ff[x]]=ff[y], Link(t);
            if(++k==n) break;
        }
    int cnt=0;
    for(int i=Q,x,y,t; i; --i)
    {
        Split(x=qx[i],y=qy[i]);
        if(type[i]==1) Ans[++cnt]=val[pos[y]];
        else if(t=id[x][y],val[pos[y]]>e[t].val){
            Cut(pos[y]), Link(t);
        }
    }
    while(cnt) printf("%d\n",Ans[cnt--]);

    return 0;
}

原文地址:https://www.cnblogs.com/SovietPower/p/8673223.html

时间: 2025-01-07 06:27:53

洛谷.4172.[WC2006]水管局长(LCT Kruskal)的相关文章

洛谷P4172 [WC2006]水管局长 (LCT,最小生成树)

思路分析 在一个图中,要求路径上最大边边权最小,就不难想到最小生成树.而题目中有删边的操作,那肯定是要动态维护啦.直接上LCT维护边权最小值(可以参考一下蒟蒻的Blog) 这时候令人头疼的问题又冒出来了......删掉一条边以后,又不好从树断开后的两边选出最小的边在连上.这是根本维护不了的. 于是蒟蒻又get到了一个新套路--顺序解决不了的问题,可以离线询问,反过来处理.原来的删边变成了加边,就很方便了.直接split找出环上的最大边,当前要加的边比它小就替换掉. 一个做法的问题:在反过来初始化

Luogu4712 WC2006 水管局长 LCT

传送门 老套路,删边换成加边 然后就变成了$LCT$维护最小生成树的裸题 化边为点,对于每一个点记录链上最大值和对应的边的编号,每一次加入一条边时考虑是否能通过割掉当前树上路径上的最大权值的边获得一个更小的生成树. 1 #include<bits/stdc++.h> 2 //This code is written by Itst 3 using namespace std; 4 5 inline int read(){ 6 int a = 0; 7 bool f = 0; 8 char c

[bzoj2594][Wc2006]水管局长数据加强版

论蒟蒻的自我修养T_T.. 和noi2014魔法森林基本一样...然而数据范围大得sxbk...100w你告诉我(n+m)log(n+m)可过?[掀桌] 蒟蒻又蠢了..复杂度应该是O((n+q)log(n+m))吧.. 一开始数组开太小re了两发(要开到maxn+maxm),然后又开太大mle一发,然后无限tle...把记录类型全改成数组还是tle.... 最后把非lct部分改得和黄学长全部一样终于20+s卡过去了......... 然后发现自己原来是有个地方写萎了..一开始把没被删的边做kru

【BZOJ 2594】 [Wc2006]水管局长数据加强版

2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MB Submit: 1138  Solved: 364 [Submit][Status] Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等

bzoj 2594: [Wc2006]水管局长数据加强版 动态树

2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MBSubmit: 934  Solved: 291[Submit][Status] Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径

BZOJ 2594: [Wc2006]水管局长数据加强版(kruskal + LCT)

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

BZOJ_2594_[Wc2006]水管局长数据加强版_LCT

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

P4172 [WC2006]水管局长

[LCT]P4172水管局长 \(Solution\) 如果没有删除,那么就是维护一个最小生成树,然后倍增求两点之间的最大边权(货车运输). 因为有删边操作,想到LCT,但这是删除,最大值不满足减法,所以不好搞. 但注意到只有删除没有添加,所以我们可以倒过来处理,一条一条边link维护最小生成树以及两点间最大值,这样最大值就变成可加的了. 倒着处理,如果要加一条边u->v,那么先查询u->v的最大边权(假如这条边为x->y),如果要加的边权比这还大,那么就忽略(贪心),否则就删掉x-&g

[BZOJ2594] [Wc2006]水管局长数据加强版(LCT + kruskal + 离线)

传送门 WC这个题真是丧心病狂啊,就是想学习一下怎么处理边权,给我来了这么一个破题! ORZ hzwer 临摹黄学长代码233 但还是复杂的一匹 理一下思路吧 题目大意:给定一个无向图,多次删除图中的某一条边,求两点间路径最大值的最小值 求两点间的路径最大值的最小值的话,可以求最小生成树,那么这个值就是最小生成树上两点间路径上的最大值 但是题目要求是删除边,LCT维护最小生成树不支持删边操作,那么就离线处理,倒着加边,用LCT维护. 就是这个离线处理是最恶心的. 来说说如何处理边权,把边也抽象成