[WC2006]水管局长——Link Cut Tree加边维护MST

题目大意:

给定一个图,有两种操作,一种询问从x到y的路径中经过的边的最大值得最小值,第二种操作删除一条边。

思路:

离线操作,反着来做,每次加边询问环上面最大的边是否大于新加的边,若是删掉此边加入新边。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
void File(){
    freopen("[HNOI2010]CITY.in","r",stdin);
    freopen("[HNOI2010]CITY.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define ll long long
#define inf (0x3f3f3f3f)
int _max(int _,int __){return _>__ ? _ : __;}
int _min(int _,int __){return _<__ ? _ : __;}
const int maxn=1e3+10;
const int maxm=1e5+10;
struct edge{
    int u,v,w;
    bool operator < (const edge &tt) const {
        return w<tt.w;
    }
}E[maxm];
int n,m,q,cnt;
struct lct{
#define lc ch[rt][0]
#define rc ch[rt][1]
#define rel(x) (ch[fa[x]][1]==x)
    int va[maxn+maxm],Maxva[maxn+maxm],Maxnum[maxn+maxm],fa[maxn+maxm],ch[maxn+maxm][2],q[maxn+maxm],top;
    bool tag[maxn+maxm];
    bool isrt(int rt){return ch[fa[rt]][0]!=rt && ch[fa[rt]][1]!=rt;}
    void pushdown(int rt){if(tag[rt])tag[rt]^=1,tag[lc]^=1,tag[rc]^=1,swap(lc,rc);}
    void pushup(int rt){
        Maxva[rt]=_max(va[rt],_max(Maxva[lc],Maxva[rc]));
        if(Maxva[rt]==va[rt])Maxnum[rt]=rt;
        else if(Maxva[rt]==Maxva[lc])Maxnum[rt]=Maxnum[lc];
        else Maxnum[rt]=Maxnum[rc];
    }
    void rotate(int rt){
        int f=fa[rt],r=rel(rt);
        fa[rt]=fa[f];if(!isrt(f))ch[fa[f]][rel(f)]=rt;
        fa[ch[rt][r^1]]=f;ch[f][r]=ch[rt][r^1];
        fa[f]=rt;ch[rt][r^1]=f;
        pushup(f);pushup(rt);
    }
    void splay(int rt){
        top=1;q[top]=rt;
        int u=rt;
        while(!isrt(u))u=fa[u],q[++top]=u;
        DREP(i,top,1)pushdown(q[i]);
        while(!isrt(rt)){
            int f=fa[rt];
            if(!isrt(f))rotate(rel(f)==rel(rt) ? f : rt);
            rotate(rt);
        }
    }
    void access(int rt){for(int las=0;rt;las=rt,rt=fa[rt])splay(rt),rc=las,pushup(rt);}
    void makert(int rt){access(rt);splay(rt);tag[rt]^=1;}
    int findrt(int rt){access(rt);splay(rt);while(lc)rt=lc;return rt;}
    bool con(int x,int y){makert(x);return (findrt(y)==x);}
    void split(int x,int y){makert(x);access(y);splay(y);}
    void link(int x,int y){if(con(x,y))return;makert(x);fa[x]=y;}
    void cut(int x,int y){if(!con(x,y))return;split(x,y);if(ch[y][0]==x)ch[y][0]=0,fa[x]=0,pushup(y);}
    int query_num(int x,int y){split(x,y);return Maxnum[y];}
    int query(int x,int y){split(x,y);return Maxva[y];}
}T;
int ans[maxm],e[maxn][maxn];
struct node{
    int key;
    int x,y;
}Query[maxm];
bool vis[maxn][maxn];
int main(){
    File();
    scanf("%d%d%d",&n,&m,&q);
    REP(i,1,m){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        ++cnt;
        E[cnt].u=u;E[cnt].v=v;
        E[cnt].w=w;
        e[u][v]=e[v][u]=cnt;
    }
    REP(i,1,n)T.Maxnum[i]=i;
    REP(i,1,m)T.va[i+n]=T.Maxva[i+n]=E[i].w,T.Maxnum[i+n]=i+n;
    REP(i,1,q){
        scanf("%d%d%d",&Query[i].key,&Query[i].x,&Query[i].y);
        if(Query[i].key==2){
            vis[Query[i].x][Query[i].y]=1;
            vis[Query[i].y][Query[i].x]=1;
        }
    }
    REP(i,1,m){
        int u=E[i].u,v=E[i].v,w=E[i].w;
        if(vis[u][v])continue;
        if(!T.con(u,v))T.link(i+n,u),T.link(i+n,v);
        else{
            int num=T.query_num(u,v);
            if(T.va[num]<=w)continue;
            T.cut(num,E[num-n].u);
            T.cut(num,E[num-n].v);
            T.link(i+n,u);
            T.link(i+n,v);
        }
    }
    int cnt1=0;
    DREP(i,q,1){
        int u=Query[i].x,v=Query[i].y,w=E[e[u][v]].w;
        if(Query[i].key==1)ans[++cnt1]=T.query(u,v);
        else{
            int num=T.query_num(u,v);
            if(T.va[num]<=w)continue;
            T.cut(num,E[num-n].u);
            T.cut(num,E[num-n].v);
            T.link(e[u][v]+n,u);
            T.link(e[u][v]+n,v);
        }
    }
    DREP(i,cnt1,1)printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值