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

洛谷题目传送门

思路分析

在一个图中,要求路径上最大边边权最小,就不难想到最小生成树。而题目中有删边的操作,那肯定是要动态维护啦。直接上LCT维护边权最小值(可以参考一下蒟蒻的Blog
这时候令人头疼的问题又冒出来了。。。。。。删掉一条边以后,又不好从树断开后的两边选出最小的边在连上。这是根本维护不了的。
于是蒟蒻又get到了一个新套路——顺序解决不了的问题,可以离线询问,反过来处理。原来的删边变成了加边,就很方便了。直接split找出环上的最大边,当前要加的边比它小就替换掉。
一个做法的问题:在反过来初始化最后时刻的最小生成树的时候,kruskal加边时还不是很好判断当前枚举到的边有没有在中途断掉。如果要搞一个set或者map之类的东西,不会很麻烦?
然后看到N居然只有1000?!于是直接开邻接矩阵标记一下就好啦。
卡常+O2 600+ms水到榜上来

#include<cstdio>
#include<algorithm>
using namespace std;
#define R register int
#define I inline void
#define lc c[x][0]
#define rc c[x][1]
const int N=1009,M=2009,L=100009;
int f[M],c[M][2],v[M],mx[M],ex[M];
//ex存放LCT中代表边的点的子节点,为卡常cut帮忙
int ff[N],l[N][N],k[L],a[L],b[L],ans[L];
bool r[M],g[N][N];//暴力搞邻接矩阵
struct EDGE{
    int u,v,l;
    inline bool operator<(EDGE x)const{
        return l<x.l;
    }
}e[L];
char ch;int z;
inline int in(){
    while((ch=getchar())<'-');
    z=ch&15;
    while((ch=getchar())>'-')z*=10,z+=ch&15;
    return z;
}
inline bool nroot(R x){return c[f[x]][0]==x||c[f[x]][1]==x;}
inline int get(R x,R y){return v[x]>v[y]?x:y;}
I pushup(R x){
    mx[x]=get(x,get(mx[lc],mx[rc]));
}
I pushdown(R x){
    if(r[x]){
        R t=lc;
        r[lc=rc]^=1;r[rc=t]^=1;r[x]=0;
    }
}
I pushall(R x){
    if(nroot(x))pushall(f[x]);
    pushdown(x);
}
I rotate(R x){
    R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
    if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
    f[w]=y;f[y]=x;f[x]=z;
    pushup(y);
}
I splay(R x){
    R y=x;
    pushall(x);
    while(nroot(x)){
        if(nroot(y=f[x]))
            rotate((c[y][0]==x)^(c[f[y]][0]==y)?x:y);
        rotate(x);
    }
    pushup(x);
}
I access(R x){
    for(R y=0;x;x=f[y=x])
        splay(x),rc=y,pushup(x);
}
I mroot(R x){
    access(x);splay(x);
    r[x]^=1;
}
#define link(E)\
    mroot(x);f[f[ex[E]=x]=E]=y;\
    v[E]=l[x][y];pushup(E)
//不正常的link和cut(也总结在blog里)
I cut(R x){
    access(ex[x]);splay(x);
    lc=rc=f[lc]=f[rc]=0;
}
int getf(R x){
    if(x==ff[x])return x;
    return ff[x]=getf(ff[x]);
}
int main(){
    R n,m,Q,i,x,y,tmp,cnt;
    n=in();m=in();Q=in();
    for(i=1;i<=m;++i){
        x=e[i].u=in();y=e[i].v=in();
        l[x][y]=l[y][x]=e[i].l=in();
    }
    for(i=1;i<=Q;++i){
        k[i]=in();a[i]=in();b[i]=in();
        if(k[i]&2)g[a[i]][b[i]]=g[b[i]][a[i]]=1;
    }
    for(i=0;i<=n;++i)
        ff[i]=i;
    //接下来还是走一遍kruskal
    sort(e+1,e+m+1);
    for(cnt=n*2-1,i=1;cnt>n;++i){
        x=e[i].u;y=e[i].v;
        if(!g[x][y]&&getf(x)!=getf(y)){
            link(cnt);--cnt;
            ff[ff[x]]=ff[y];
        }
    }
    for(cnt=0,i=Q;i;--i){
        mroot(x=a[i]);
        access(y=b[i]);splay(y);
        if(k[i]&1)ans[++cnt]=v[mx[y]];//答案压到栈里面,最后反过来弹
        else if(v[mx[y]]>l[x][y]){
            cut(tmp=mx[y]);link(tmp);
        }
    }
    while(cnt)printf("%d\n",ans[cnt--]);
    return 0;
}

转载于:https://www.cnblogs.com/flashhu/p/8590847.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值