「WC 2006」水管局长

题目链接

戳我

\(Solution\)

这道题实际上是维护一个最小生成树,因为正的搞不好搞,所以反着搞会比较好,现将没有没删掉的边留下来生成一颗最小生成树,再加边就好了,现在\(LCT\)

来看看怎么维护

对于一个最小生成树,加一条边后会是一个环,在环上删掉一个最大的边,还是一个最小生成树。所以我们对于加边只要判断这条边和最小生成树上最大边的大小,如果小于,则将这条边加入,原最小生成树上最大的边删除,如果大于不需要管他。

但是\(LCT\)只能维护点权,不能维护边权,不妨将这个边看成点即可

加入\((x,y)的边\)就是\(link(x,id),link(y,id),id\)为这条边的编号
\(cut\)同理

\(Code\)

#include<bits/stdc++.h>
#define rg register
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return f*x;
}
struct node {
    int fa,v,lazy,ch[2];
}a[1100001];
int v[1100001],pre[100001];
map<int,int> f[100001];
int vis[1000001];
inline bool nroot(int x){
    return a[a[x].fa].ch[0]==x||a[a[x].fa].ch[1]==x;
}
inline int max(int x,int y){
    return v[x]>v[y]?x:y;
}
inline void pushup(int x){
    a[x].v=max(a[a[x].ch[0]].v,max(a[a[x].ch[1]].v,x));
}
inline void work(int x){
    int t=a[x].ch[0];
    a[x].ch[0]=a[x].ch[1],a[x].ch[1]=t,a[x].lazy^=1;
}
inline void pushdown(int x){
    if(a[x].lazy)
        work(x),a[a[x].ch[0]].lazy^=1,a[a[x].ch[1]].lazy^=1;
}
inline void rotate(int x){
    int y=a[x].fa,z=a[y].fa,k=(a[y].ch[1]==x);
    if(nroot(y)) a[z].ch[a[z].ch[1]==y]=x;
    a[x].fa=z,a[y].ch[k]=a[x].ch[k^1],a[a[x].ch[k^1]].fa=y;
    a[x].ch[k^1]=y,a[y].fa=x;
    pushup(x),pushup(y);
}
inline void down(int x){
    if(nroot(x)) down(a[x].fa);
    pushdown(x);
}
inline void splay(int x){
    down(x);
    while(nroot(x)){
        int y=a[x].fa,z=a[y].fa;
        if(nroot(y))
            (a[y].ch[1]==x)^(a[z].ch[1]==y)?rotate(x):rotate(y);
        rotate(x);
    }
    pushup(x);
}
inline void access(int x){
    int y=0;
    while(x) splay(x),a[x].ch[1]=y,pushup(y=x),x=a[x].fa;
}
inline void makeroot(int x){
    access(x),splay(x),a[x].lazy^=1;
}
inline void splix(int x,int y){
    makeroot(x),access(y),splay(y);
}
inline int findroot(int x){
    access(x),splay(x);
    while(a[x].ch[0]) pushdown(x),x=a[x].ch[0];
    splay(x);
    return x;
}
inline void link(int x,int y){
    makeroot(x);
    if(findroot(y)!=x)
        a[x].fa=y;
}
inline void cut(int x,int y){
    makeroot(x);
    if(findroot(y)!=x||a[y].fa!=x||a[y].ch[0]) return ;
    a[y].fa=a[x].ch[1]=0,pushup(x);
}
struct node1{
    int x,y,z;
}b[1000001];
inline bool cmp(const node1 & a , const node1 & b ){
    return a.z<b.z;
}
inline int find(int x){
    return pre[x]==x?x:pre[x]=find(pre[x]);
}
int X[100001],Y[100001],opt[100001],n,m,q,ans[100001],tot;
inline void MST(){
    for(int i=1;i<=n;i++)
        pre[i]=i;
    for(int i=1;i<=m;i++){
        int fx=find(b[i].x),fy=find(b[i].y);
        if(!vis[i]&&fx!=fy)
            link(b[i].x,i+n),link(b[i].y,i+n),pre[fx]=fy;
    }
}
int main(){
    n=read(),m=read(),q=read();
    for(rg int i=1;i<=m;i++)
        b[i].x=read(),b[i].y=read(),b[i].z=read();
    sort(b+1,b+1+m,cmp);
    for(rg int i=1;i<=m;i++)
        f[b[i].x][b[i].y]=f[b[i].y][b[i].x]=i+n,v[i+n]=b[i].z;
    for(rg int i=1;i<=q;i++){
        opt[i]=read(),X[i]=read(),Y[i]=read();
        if(opt[i]==2) vis[f[X[i]][Y[i]]-n]=1;
    }
    MST();
    for(rg int i=q;i>=1;i--){
        splix(X[i],Y[i]);
        if(opt[i]==1)
            ans[++tot]=v[a[Y[i]].v];
        else{
            if(v[a[Y[i]].v]>v[f[X[i]][Y[i]]]){
                int x=a[Y[i]].v;
                cut(b[x-n].x,x),cut(b[x-n].y,x),link(X[i],f[X[i]][Y[i]]),link(Y[i],f[X[i]][Y[i]]);
            }
        }
    }
    for(rg int i=tot;i>=1;i--)
        printf("%d\n",ans[i]);
    return 0;
}
posted @ 2019-04-18 11:58  撤云  阅读(180)  评论(0编辑  收藏  举报
……