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

7 篇文章 0 订阅
5 篇文章 0 订阅
题目大意 
给一张带权无向图,无重边和自环,有如下操作: 
删除某条边,保证这条边在删除前一定存在,并且不破坏原图连通性; 

询问两点之间所有路径中最小权值的最大值是多少;


这道题真不错啊。。是道好题。

题解:

首先,这一题的权值在边上,所以我们需要像上一题一样,转化一下,弄多一个点表示边权。

然后是一个很重要的推论(也可以说证明),题目所求的答案一定在当前的最小生成树(森林)上。 我认为这个证明读者十分需要自己好好yy一下,不懂的再自行百度,其实也不难懂,那个论文的证明我倒不是很懂(๑•̀ㅂ•́)و✧。

最后,那么我们知道了要维护一棵最小生成树(森林),可是删边没办法维护啊....b( ̄▽ ̄)d

所以我们可以:离线! 倒过来做便意味着删边变成加边,我们在加边的时候找出x y当前路径上的最大值 如果比加入的边大,我们就删掉那条最大的,加入目前的新边。


细节挺多的。。其实中间还有三次快排以及二分找边。。记得加读入优化!BZOJ都教你怎么写了

打到你累shi。。。

代码:忽然觉得我的代码还挺好看和简洁的~     (向hzwer学习~)

#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
#include
      
      
       
       
#include
       
       
         #define N 1200010 using namespace std; typedef long long LL; struct edge{int x,y,c,id,d;}e[1000010]; struct node{int f,x,y,ans,id;}q[100005]; int fa[N],n,m,p,c[N][2],st[N],w[N],mx[N]; bool rev[N]; int cmpa(edge x1,edge x2){return x1.c 
        
          w[mx[x]])mx[x]=mx[l]; if(w[mx[r]]>w[mx[x]])mx[x]=mx[r]; } void pushdown(int x) { int l=c[x][0],r=c[x][1]; if(rev[x]) { rev[x]=0,rev[l]^=1,rev[r]^=1; swap(c[x][0],c[x][1]); } } void rotate(int x) { int y=fa[x],z=fa[y],a=c[y][1]==x,b=c[z][1]==y,g=c[x][!a]; if(!Rt(y))c[z][b]=x; fa[g]=y,c[y][a]=g; fa[y]=x,c[x][!a]=y; fa[x]=z; pushup(y); pushup(x); } void splay(int x) { int top=0,i; for(i=x;!Rt(i);i=fa[i])st[++top]=i; st[++top]=i; for(i=top;i;i--)pushdown(st[i]); while(!Rt(x)) { int y=fa[x],z=fa[y],a=c[y][1]==x,b=c[z][1]==y; if(!Rt(y)) { if(a==b)rotate(y); else rotate(x); } rotate(x); } } void access(int x) { int last=0; while(x) { splay(x); c[x][1]=last; pushup(x); last=x,x=fa[x]; } } void make_root(int x) { access(x); splay(x); rev[x]^=1; } void split(int x,int y) { make_root(x); access(y); splay(y); } void link(int x,int y) { make_root(x); fa[x]=y; } void cut(int x,int y) { split(x,y); fa[x]=c[y][0]=0; } int find(int x,int y) { int l=1,r=m; while(l<=r) { int mid=(l+r)>>1; if(e[mid].x==x && e[mid].y==y)return mid; if(e[mid].x 
         
           '9')ch=getchar(); while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x; } int f[100010]; int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);} int main() { int i,x,y,fx,fy,k; n=read(),m=read(),p=read(); for(i=1;i<=n;i++)f[i]=i; for(i=1;i<=m;i++) { e[i].x=read(),e[i].y=read(),e[i].c=read(); if(e[i].x>e[i].y)swap(e[i].x,e[i].y); } sort(e+1,e+1+m,cmpa); for(i=1;i<=m;i++) e[i].id=i,w[n+i]=e[i].c,mx[n+i]=n+i; sort(e+1,e+1+m,cmpb); for(i=1;i<=p;i++) { q[i].f=read(),q[i].x=read(),q[i].y=read(); if(q[i].f==2) { if(q[i].x>q[i].y)swap(q[i].x,q[i].y); x=find(q[i].x,q[i].y); e[x].d=1,q[i].id=e[x].id; } } sort(e+1,e+1+m,cmpc); int s=0; for(i=1;i<=m;i++) if(!e[i].d) { x=e[i].x,y=e[i].y,fx=getf(x),fy=getf(y); if(fx!=fy) { f[fx]=fy; link(x,i+n); link(y,i+n); s++; if(s==n-1)break; } } for(i=p;i;i--) { x=q[i].x,y=q[i].y,k=q[i].id; split(x,y); s=mx[y]; if(q[i].f==1)q[i].ans=w[s]; else if(e[k].c 
           
          
         
       
      
      
     
     
    
    
   
   

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值