• link cut tree 入门


    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构。

    link cut tree:研究popoqqq那个神ppt。

    bzoj1036:维护access操作就可以了。

    #include<cstdio> 
    #include<cstring> 
    #include<cctype> 
    #include<algorithm> 
    #include<queue> 
    using namespace std; 
    #define rep(i,s,t) for(int i=s;i<=t;i++) 
    #define dwn(i,s,t) for(int i=s;i>=t;i--) 
    #define clr(x,c) memset(x,c,sizeof(x)) 
    #define qwq(x) for(edge *o=head[x];o;o=o->next) 
    int read(){ 
        int x=0,f=1;char c=getchar(); 
        while(!isdigit(c)){ 
            if(c=='-') f=-1;c=getchar(); 
        } 
        while(isdigit(c)) x=x*10+c-'0',c=getchar(); 
        return x*f; 
    } 
    const int nmax=3e4+5; 
    const int inf=0x7f7f7f7f; 
    struct edge{ 
        int to;edge *next; 
    }; 
    edge es[nmax<<1],*pt=es,*head[nmax]; 
    void add(int u,int v){ 
        pt->to=v;pt->next=head[u];head[u]=pt++; 
        pt->to=u;pt->next=head[v];head[v]=pt++; 
    } 
    int n,m,fa[nmax],c[nmax][2],sm[nmax],mx[nmax],q[nmax],w[nmax];bool vis[nmax]; 
    void bfs(){ 
        int l=1,r=1,x;q[r]=1;vis[1]=1; 
        while(l<=r){ 
            x=q[l++]; 
            qwq(x) if(!vis[o->to]) fa[o->to]=x,q[++r]=o->to,vis[o->to]=1; 
        } 
    } 
    bool pdrt(int x){ 
        return c[fa[x]][0]!=x&&c[fa[x]][1]!=x; 
    } 
    void update(int x){ 
        int l=c[x][0],r=c[x][1]; 
        sm[x]=sm[l]+sm[r]+w[x];mx[x]=max(w[x],max(mx[l],mx[r])); 
    } 
    void rotate(int x){ 
        int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; 
        if(!pdrt(y)) if(c[z][0]==y) c[z][0]=x;else c[z][1]=x; 
        fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 
        c[y][l]=c[x][r];c[x][r]=y; 
        update(y);update(x); 
    } 
    void splay(int x){ //把一个点伸展到它所在的重链的根。  
        int y,z;//fa[x]=y表示以x为根的splay树的父亲是y,但是y的两个儿子(c[y][0]和c[y][1])中没有一个是x 
        while(!pdrt(x)){ 
            y=fa[x];z=fa[y]; 
            if(!pdrt(y)) if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y); 
            rotate(x); 
        } 
    } 
    int access(int x){ 
        int t=0; 
        while(x) splay(x),c[x][1]=t,t=x,update(x),x=fa[x]; 
        return t; 
        //考虑点u,v。假设先access(u)了,那么access(lca(u,v))时lca(u,v)是原splay的根节点, 
        //左边的是深度比它小的点,即是lca(u,v)到根的链。 说明access的操作是正确的。  
    } 
    void qsum(int u,int v){ 
        access(u);int lca=access(v);splay(u); 
        if(lca==u) printf("%d
    ",w[u]+sm[c[lca][1]]); 
        else printf("%d
    ",w[lca]+sm[c[lca][1]]+sm[u]); 
    } 
    void qmax(int u,int v){ 
        access(u);int lca=access(v);splay(u); 
        if(lca==u) printf("%d
    ",max(w[u],mx[c[lca][1]])); 
        else printf("%d
    ",max(w[lca],max(mx[c[lca][1]],mx[u]))); 
    } 
    int main(){ 
        n=read();int u,v,d;mx[0]=-inf; 
        rep(i,1,n-1) u=read(),v=read(),add(u,v); 
        rep(i,1,n) sm[i]=mx[i]=w[i]=read();bfs(); 
        m=read();char ch[11]; 
        rep(i,1,m){ 
            scanf("%s",ch);u=read(),v=read(); 
            if(ch[1]=='H') splay(u),w[u]=v,update(u); 
            else if(ch[1]=='S') qsum(u,v); 
            else qmax(u,v); 
        } 
        return 0; 
    } 
    

     bzoj2049:link cut tree 模版题。

    #include<cstdio> 
    #include<cstring> 
    #include<cctype> 
    #include<algorithm> 
    using namespace std; 
    #define rep(i,s,t) for(int i=s;i<=t;i++) 
    #define dwn(i,s,t) for(int i=s;i>=t;i--) 
    #define clr(x,c) memset(x,c,sizeof(x)) 
    #define qwq(x) for(edge *o=head[x];o;o=o->next) 
    int read(){ 
        int x=0,f=1;char c=getchar(); 
        while(!isdigit(c)){ 
            if(c=='-') f=-1;c=getchar(); 
        } 
        while(isdigit(c)) x=x*10+c-'0',c=getchar(); 
        return x*f; 
    } 
    const int nmax=1e4+5; 
    int n,m,fa[nmax],c[nmax][2],st[nmax],rev[nmax]; 
    bool pdrt(int x){ 
        return c[fa[x]][0]!=x&&c[fa[x]][1]!=x; 
    } 
    void pushdown(int x){ 
        if(rev[x]){ 
            int l=c[x][0],r=c[x][1]; 
            rev[x]^=1;rev[l]^=1;rev[r]^=1; 
            swap(c[x][0],c[x][1]); 
        } 
    } 
    void rotate(int x){ 
        int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; 
        if(!pdrt(y)) if(c[z][0]==y) c[z][0]=x;else c[z][1]=x; 
        fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 
        c[y][l]=c[x][r];c[x][r]=y; 
    } 
    void splay(int x){ 
        int top=0,y,z;st[++top]=x; 
        for(int i=x;!pdrt(i);i=fa[i]) st[++top]=fa[i]; 
        dwn(i,top,1) pushdown(st[i]); 
        while(!pdrt(x)){ 
            y=fa[x];z=fa[y]; 
            if(!pdrt(y)) if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y); 
            rotate(x); 
        } 
    } 
    void access(int x){ 
        int t=0; 
        while(x) splay(x),c[x][1]=t,t=x,x=fa[x]; 
    } 
    void rever(int x){ 
        access(x);splay(x);rev[x]^=1; 
    } 
    void link(int x,int y){ 
        rever(x);fa[x]=y; 
    } 
    void cut(int x,int y){ 
        rever(x);access(y);splay(y);c[y][0]=fa[x]=0; 
    } 
    int find(int x){ 
        access(x);splay(x); 
        int y=x;while(c[y][0]) y=c[y][0]; 
        return y; 
    } 
    int main(){ 
        n=read(),m=read();int x,y;char ch[11]; 
        rep(i,1,m){ 
            scanf("%s",ch);x=read(),y=read(); 
            if(ch[0]=='C') link(x,y); 
            else if(ch[0]=='D') cut(x,y); 
            else { 
                if(find(x)==find(y)) puts("Yes"); 
                else puts("No"); 
            } 
        } 
        return 0; 
    } 
    

    我这二逼智商。。。真的够了。。。。

    upd9.27 重新理解了两次link cut tree 然后打起代码来顺多了。。。

    bzoj2002:还是基本的操作

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define clr(x,c) memset(x,c,sizeof(x))
    int read(){
    	int x=0;char c=getchar();
    	while(!isdigit(c)) c=getchar();
    	while(isdigit(c)) x=x*10+c-'0',c=getchar();
    	return x;
    }
    const int nmax=2e5+5;
    const int inf=0x7f7f7f7f;
    int fa[nmax],c[nmax][2],sz[nmax],q[nmax],nxt[nmax];
    bool rev[nmax];
    bool isroot(int x){
    	return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
    }
    void pushup(int x){
    	sz[x]=sz[c[x][0]]+sz[c[x][1]]+1;
    }
    void pushdown(int x){
    	if(rev[x]){
    		int l=c[x][0],r=c[x][1];
    		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],l=c[y][1]==x,r=l^1;
    	if(!isroot(y)) c[z][c[z][1]==y]=x;
    	fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
    	c[y][l]=c[x][r];c[x][r]=y;
    	pushup(y);pushup(x);
    }
    void splay(int x){
    	int cnt=0,y,z;q[++cnt]=x;
    	for(int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];
    	dwn(i,cnt,1) pushdown(q[i]);
    	while(!isroot(x)){
    		y=fa[x],z=fa[y];
    		if(!isroot(y)){
    			if(c[y][0]==x^c[z][0]==y) rotate(x);
    			else rotate(y);
    		}
    		rotate(x);
    	}
    }
    void access(int x){
    	int t=0;
    	while(x) splay(x),c[x][1]=t,t=x,x=fa[x]; //这里应该是要pushup(x)的。但是为什么不加也能A啊TAT
    }
    void rever(int x){
    	access(x),splay(x),rev[x]^=1;
    }
    void link(int x,int y){
    	rever(x);fa[x]=y;
    }
    void cut(int x,int y){
    	rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
    }
    int main(){
    	int n=read(),u,v,d;
    	rep(i,1,n){
    		u=read();fa[i]=min(n+1,i+u);
    		sz[i]=1;nxt[i]=fa[i];
    	}
    	sz[n+1]=1;
    	int m=read();
    	while(m--){
    		u=read();
    		if(u==1){
    			rever(n+1);v=read()+1;
    			access(v);splay(v);
    			printf("%d
    ",sz[c[v][0]]);
    		}else{
    			v=read()+1;d=read();u=min(n+1,v+d);
    			cut(v,nxt[v]);link(v,u);nxt[v]=u;
    		}
    	}
    	return 0;
    }
    /*
    4                              
    1 2 1 1						   
    3
    1 1
    2 1 1
    1 1
    */
    

    bzoj3282:还是基本操作

    因为pushup我放在了x=fa[x]后面调了一节晚自修。 

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define clr(x,c) memset(x,c,sizeof(x))
    int read(){
    	int x=0;char c=getchar();
    	while(!isdigit(c)) c=getchar();
    	while(isdigit(c)) x=x*10+c-'0',c=getchar();
    	return x;
    }
    const int nmax=3e5+5;
    const int inf=0x7f7f7f7f;
    int fa[nmax],c[nmax][2],sz[nmax],w[nmax],q[nmax];
    bool rev[nmax];
    void pushup(int x){
    	sz[x]=w[x]^sz[c[x][0]]^sz[c[x][1]];
    }
    void pushdown(int x){
    	if(rev[x]){
    		int l=c[x][0],r=c[x][1];
    		rev[x]=0;rev[l]^=1;rev[r]^=1;
    		swap(c[x][0],c[x][1]);
    	}
    }
    bool isroot(int x){
    	return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
    }
    void rotate(int x){
    	int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
    	if(!isroot(y)) c[z][c[z][1]==y]=x;
    	fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
    	c[y][l]=c[x][r];c[x][r]=y;
    	pushup(y);pushup(x);
    }
    void splay(int x){
    	int cnt=0,y,z;q[++cnt]=x;
    	for(int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];
    	dwn(i,cnt,1) pushdown(q[i]);
    	while(!isroot(x)){
    		y=fa[x];z=fa[y];
    		if(!isroot(y)){
    			if(c[y][0]==x^c[z][0]==y) rotate(x);
    			else rotate(y);
    		}
    		rotate(x);
    	}
    }
    void access(int x){
    	int t=0;
    	while(x) splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x];
    }
    //因为pushup我放在了x=fa[x]后面调了一节晚自修。 
    void rever(int x){
    	access(x),splay(x),rev[x]^=1;
    }
    void link(int x,int y){
    	rever(x);fa[x]=y;
    }
    void cut(int x,int y){
    	rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
    }
    int find(int x){
    	access(x);splay(x);
    	while(c[x][0]) x=c[x][0];
    	return x;
    }
    int main(){
    	int n=read(),m=read(),u,x,y;
    	rep(i,1,n) sz[i]=w[i]=read();
    	while(m--){
    		u=read(),x=read(),y=read();
    		if(u==0) {
    			rever(x);access(y),splay(y);
    			printf("%d
    ",sz[y]);
    		}else if(u==1) {
    			if(find(x)!=find(y)) link(x,y);
    		}else if(u==2) {
    			if(find(x)==find(y)) cut(x,y);
    		}else {
    			access(x),splay(x),w[x]=y,pushup(x);
    		}
    	}
    	return 0;
    }
    

    bzoj2843&1180:还是基本操作

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    #define rep(i,s,t) for(register int i=s;i<=t;i++)
    #define dwn(i,s,t) for(register int i=s;i>=t;i--)
    #define clr(x,c) memset(x,c,sizeof(x))
    #define lc c[x][0]
    #define rc c[x][1]
    int read(){
    	int x=0;char c=getchar();
    	while(!isdigit(c)) c=getchar();
    	while(isdigit(c)) x=x*10+c-'0',c=getchar();
    	return x;
    } 
    const int nmax=3e4+5;
    const int inf=0x7f7f7f7f;
    int fa[nmax],c[nmax][2],sm[nmax],w[nmax],q[nmax];
    bool rev[nmax];
    bool isroot(int x){
    	int t=x;x=fa[x];return lc!=t&&rc!=t;
    }
    void pushup(int x){
    	sm[x]=w[x]+sm[lc]+sm[rc];
    }
    void pushdown(int x){
    	if(rev[x]){
    		rev[x]=0;rev[lc]^=1;rev[rc]^=1;
    		swap(lc,rc);
    	}
    }
    void rotate(int x){
    	int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
    	if(!isroot(y)) c[z][c[z][1]==y]=x;
    	fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
    	c[y][l]=c[x][r];c[x][r]=y;
    	pushup(y);pushup(x);
    }
    void splay(int x){
    	int cnt=0,y,z;q[++cnt]=x;
    	for(register int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];
    	dwn(i,cnt,1) pushdown(q[i]);
    	while(!isroot(x)){
    		y=fa[x];z=fa[y];
    		if(!isroot(y)) {
    			if(c[y][0]==x^c[z][0]==y) rotate(x);
    			else rotate(y);
    		}
    		rotate(x);
    	}
    }
    void access(int x){
    	int t=0;
    	while(x) splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x];
    }
    void rever(int x){
    	access(x);splay(x);rev[x]^=1;
    }
    void link(int x,int y){
    	rever(x);fa[x]=y;if(!(x&233)) splay(x);//都不splayx或者都splayx会比较慢。。。 
    }
    void cut(int x,int y){
    	rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
    }
    int find(int x){
    	access(x);splay(x);
    	while(c[x][0]) x=c[x][0];
    	return x;
    }
    int main(){
    	int n=read();
    	rep(i,1,n) w[i]=sm[i]=read();
    	int m=read(),u,v,d;char s[15];
    	while(m--){
    		scanf("%s",s);u=read(),v=read();
    		if(s[0]=='b') {
    			if(find(u)!=find(v)) link(u,v),puts("yes");
    			else puts("no");
    		}else if(s[0]=='e'){
    			if(find(u)!=find(v)) puts("impossible");
    			else rever(u),access(v),splay(v),printf("%d
    ",sm[v]);
    		}else{
    			splay(u);w[u]=v;pushup(u);
    		}
    	}
    	return 0;
    }
    

    bzoj3669:

    3669: [Noi2014]魔法森林

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 2156  Solved: 1310
    [Submit][Status][Discuss]

    Description

    为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M。初始时小E同学在号节点1,隐士则住在号节点N。小E需要通过这一片魔法森林,才能够拜访到隐士。

    魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。幸运的是,在号节点住着两种守护精灵:A型守护精灵与B型守护精灵。小E可以借助它们的力量,达到自己的目的。

    只要小E带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型守护精灵个数不少于Ai,且B型守护精灵个数不少于Bi,这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击,他才能成功找到隐士。

    由于携带守护精灵是一件非常麻烦的事,小E想要知道,要能够成功拜访到隐士,最少需要携带守护精灵的总个数。守护精灵的总个数为A型守护精灵的个数与B型守护精灵的个数之和。

    Input

    第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含4个正整数Xi,Yi,Ai,Bi,描述第i条无向边。其中Xi与Yi为该边两个端点的标号,Ai与Bi的含义如题所述。 注意数据中可能包含重边与自环。

    Output

    输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出“-1”(不含引号)。

    WerKeyTom_FTD 神犇的题解:

     我们尝试枚举路径的最大a值,那么我们只需按照a排序按顺序插入,维护1到n的b最大值即可。
    用并查集维护连通性。当加入j到k这条边时如果形成环,则删除环上的最大值。
    我们用动态树来进行维护。
    为了实现更易,将每条边看做一个点,例如第i条边两个端点是j与k,那么将i+n与j、k相连,权值放在代表边的点上。

    然后莫名其妙的空间开小了居然是TLE重新打一遍的过程中突然想到nmax开小了TAT

    #include<cstdio> 
    #include<cstring> 
    #include<cctype> 
    #include<algorithm> 
    using namespace std; 
    #define rep(i,s,t) for(int i=s;i<=t;i++) 
    #define dwn(i,s,t) for(int i=s;i>=t;i--) 
    #define clr(x,c) memset(x,c,sizeof(x)) 
    int read(){ 
        int x=0;char c=getchar(); 
        while(!isdigit(c)) c=getchar(); 
        while(isdigit(c)) x=x*10+c-'0',c=getchar(); 
        return x; 
    } 
    const int nmax=2e5+5; 
    const int maxn=1e5+5; 
    const int inf=0x7f7f7f7f; 
    int fa[nmax],c[nmax][2],mx[nmax],q[nmax],p[nmax],w[nmax]; 
    bool rev[nmax]; 
    struct edge{ 
        int u,v,a,b; 
        bool operator<(const edge &rhs)const{ 
          return a<rhs.a;} 
    }; 
    edge es[maxn]; 
    bool isroot(int x){ 
        return c[fa[x]][0]!=x&&c[fa[x]][1]!=x; 
    } 
    void pushup(int x){ 
        int l=c[x][0],r=c[x][1]; 
        mx[x]=x; 
        if(w[mx[x]]<w[mx[l]]) mx[x]=mx[l]; 
        if(w[mx[x]]<w[mx[r]]) mx[x]=mx[r]; 
    } 
    void pushdown(int x){ 
        if(rev[x]){ 
            rev[x]=0;rev[c[x][0]]^=1;rev[c[x][1]]^=1; 
            swap(c[x][0],c[x][1]); 
        } 
    } 
    void rotate(int x){ 
        int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; 
        if(!isroot(y)) c[z][c[z][1]==y]=x; 
        fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 
        c[y][l]=c[x][r];c[x][r]=y; 
        pushup(y);pushup(x); 
    } 
    void splay(int x){ 
        int cnt=0,y,z;q[++cnt]=x; 
        for(register int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i]; 
        dwn(i,cnt,1) pushdown(q[i]); 
        while(!isroot(x)){ 
            y=fa[x];z=fa[y]; 
            if(!isroot(y)){ 
                if(c[y][0]==x^c[z][0]==y) rotate(x); 
                else rotate(y); 
            } 
            rotate(x); 
        } 
    } 
    void access(int x){ 
        int t=0; 
        while(x) splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x]; 
    } 
    void rever(int x){ 
        access(x);splay(x);rev[x]^=1; 
    } 
    void link(int x,int y){ 
        rever(x);fa[x]=y;if(x&233) splay(x);
    } 
    void cut(int x,int y){ 
        rever(x);access(y);splay(y);c[y][0]=fa[x]=0;pushup(y); 
    } 
    int find(int x){ 
        return p[x]==x?x:p[x]=find(p[x]); 
    } 
    int query(int x,int y){ 
        rever(x);access(y),splay(y);return mx[y]; 
    } 
    void mins(int &a,int b){ 
        if(a>b) a=b; 
    } 
    int main(){ 
        int n=read(),m=read(),u,v,d,tmp,temp,ta,tb; 
        rep(i,1,m) es[i].u=read(),es[i].v=read(),es[i].a=read(),es[i].b=read(); 
        sort(es+1,es+m+1); 
        int ans=inf;rep(i,1,n) p[i]=i; 
        rep(i,1,m){ 
            u=es[i].u,v=es[i].v;ta=find(u),tb=find(v); 
            if(ta==tb){ 
                d=query(u,v); 
                if(w[d]>es[i].b) cut(d,es[d-n].u),cut(d,es[d-n].v); 
                else { 
                    if(find(1)==find(n)) mins(ans,es[i].a+w[query(1,n)]); 
                    continue; 
                } 
            }else p[ta]=tb; 
            w[n+i]=es[i].b;mx[n+i]=n+i; 
            link(u,n+i),link(v,n+i); 
            if(find(1)==find(n)) mins(ans,es[i].a+w[query(1,n)]); 
        } 
        printf("%d
    ",ans==inf?-1:ans); 
        return 0; 
    } 
    /*
    4 5
    1 2 19 1
    2 3 8 12
    2 4 12 15
    1 3 17 8
    3 4 1 17
    */
    

     bzoj2594:

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

    Time Limit: 25 Sec  Memory Limit: 128 MB
    Submit: 2600  Solved: 840
    [Submit][Status][Discuss]

    Description

    SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了。嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项。
    在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗、消毒等等。嘟嘟在控制中心一声令下,这些水管的准备操作同时开始,但由于各条管道的长度、内径不同,进行准备操作需要的时间可能不同。供水公司总是希望嘟嘟能找到这样一条送水路径,路径上的所有管道全都准备就绪所需要的时间尽量短。嘟嘟希望你能帮助他完成这样的一个选择路径的系统,以满足供水公司的要求。另外,由于MY市的水管年代久远,一些水管会不时出现故障导致不能使用,你的程序必须考虑到这一点。
    不妨将MY市的水管网络看作一幅简单无向图(即没有自环或重边):水管是图中的边,水管的连接处为图中的结点。
     

    Input

    输入文件第一行为3个整数:N, M, Q分别表示管道连接处(结点)的数目、目前水管(无向边)的数目,以及你的程序需要处理的任务数目(包括寻找一条满足要求的路径和接受某条水管坏掉的事实)。
    以下M行,每行3个整数x, y和t,描述一条对应的水管。x和y表示水管两端结点的编号,t表示准备送水所需要的时间。我们不妨为结点从1至N编号,这样所有的x和y都在范围[1, N]内。
    以下Q行,每行描述一项任务。其中第一个整数为k:若k=1则后跟两个整数A和B,表示你需要为供水公司寻找一条满足要求的从A到B的水管路径;若k=2,则后跟两个整数x和y,表示直接连接x和y的水管宣布报废(保证合法,即在此之前直接连接x和y尚未报废的水管一定存在)。
     

    Output

    按顺序对应输入文件中每一项k=1的任务,你需要输出一个数字和一个回车/换行符。该数字表示:你寻找到的水管路径中所有管道全都完成准备工作所需要的时间(当然要求最短)。
     将狼踩尽 神犇的题解

    题意:给出一个无向图,边有权值。定义一条路径的长度为该路径所有边的最大值。两种操作:(1)询问u到v所有路径的长度的最小值;(2)删掉某条边。

    思路:

    (1)将每个边也转化成一个点,比如边(1,2),转化成(1,3),(3,2)两个边;那么边权看做3的点权;1和2的点权可以看做0;

    (2)反着做。首先将删掉的边都删掉,询问倒着回答,那么就成了加边。

    (3)显然,路径长度就是最小生成树的最大值。因此,首先,将没有删掉的边求一次最小生成树,将最小生成树的边建立动态树。

    (4)对于查询比较简单直接查就行。

    (5)对于添加边(u,v),若u与v之前没有连通,则该边直接加进去就行,其实就是两个子树连在一起;否则,该边加进去之后会出现环,那么需要删掉环上的最大值的边。

    然后因为p[x]习惯性的写成了fa[x]然后调了一节晚自修我TAT

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define clr(x,c) memset(x,c,sizeof(x))
    int read(){
    	int x=0;char c=getchar();
    	while(!isdigit(c)) c=getchar();
    	while(isdigit(c)) x=x*10+c-'0',c=getchar();
    	return x;
    }
    const int nmax=1500005;
    const int maxn=1000005;
    const int inf=0x7f7f7f7f;
    struct edge{
    	int u,v,d,id,f;
    };
    edge es[maxn],ns[100005];
    bool cmp(edge a,edge b){
    	return a.d<b.d;
    }
    bool comp(edge a,edge b){
    	return a.id<b.id;
    }
    bool cp(edge a,edge b){
    	return a.u<b.u||a.u==b.u&&a.v<b.v;
    }
    int fa[nmax],c[nmax][2],q[nmax],mx[nmax],w[nmax],ans[nmax],p[nmax];bool rev[nmax];
    bool isroot(int x){
    	return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
    }
    void pushup(int x){
    	int l=c[x][0],r=c[x][1];mx[x]=x;
    	if(w[mx[x]]<w[mx[l]]) mx[x]=mx[l];
    	if(w[mx[x]]<w[mx[r]]) mx[x]=mx[r];
    }
    void pushdown(int x){
    	if(rev[x]){
    		rev[x]=0;rev[c[x][0]]^=1;rev[c[x][1]]^=1;
    		swap(c[x][0],c[x][1]);
    	}
    }
    void rotate(int x){
    	int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
    	if(!isroot(y)) c[z][c[z][1]==y]=x;
    	fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
    	c[y][l]=c[x][r];c[x][r]=y;
    	pushup(y);pushup(x);
    }
    void splay(int x){
    	int cnt=0,y,z;q[++cnt]=x;
    	for(int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];
    	dwn(i,cnt,1) pushdown(q[i]);
    	while(!isroot(x)){
    		y=fa[x];z=fa[y];
    		if(!isroot(y)){
    			if(c[y][0]==x^c[z][0]==y) rotate(x);
    			else rotate(y);
    		}
    		rotate(x);
    	}
    }
    void access(int x){
    	int t=0;
    	while(x) splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x];
    }
    void rever(int x){
    	access(x);splay(x);rev[x]^=1;
    }
    void link(int x,int y){
    	rever(x);fa[x]=y;
    }
    void cut(int x,int y){
    	rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
    }
    int query(int x,int y){
    	rever(x);access(y);splay(y);return mx[y];
    }
    int find(int x,int y,int m){
    	int l=1,r=m,mid;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(es[mid].u<x||es[mid].u==x&&es[mid].v<y) l=mid+1;
    		else if(es[mid].u==x&&es[mid].v==y) return mid;
    		else r=mid-1;
    	}
    }
    int ff(int x){
    	return p[x]==x?x:p[x]=ff(p[x]);
    }
    int main(){
    	int n=read(),m=read(),q=read(),tmp,temp,u,v,d,ta,tb;
    	rep(i,1,m) {
    		es[i].u=read(),es[i].v=read(),es[i].d=read();
    		if(es[i].u>es[i].v) swap(es[i].u,es[i].v);
    	}
    	sort(es+1,es+m+1,cmp);
    	rep(i,1,m) es[i].id=i,w[n+i]=es[i].d,mx[n+i]=n+i;
    	sort(es+1,es+m+1,cp);
    	rep(i,1,q) {
    		ns[i].d=read(),ns[i].u=read(),ns[i].v=read();
    		if(ns[i].u>ns[i].v) swap(ns[i].u,ns[i].v);
    		if(ns[i].d==2) tmp=find(ns[i].u,ns[i].v,m),es[tmp].f=1,ns[i].id=es[tmp].id;
    	}
    	sort(es+1,es+m+1,comp);
    	int cnt=0;rep(i,1,n) p[i]=i;
    	rep(i,1,m) if(!es[i].f){
    		u=es[i].u;v=es[i].v;ta=ff(u);tb=ff(v);
    		if(ta!=tb){
    			p[ta]=tb;link(u,i+n);link(v,i+n);//因为这里的p习惯性的打成了fa调了一节晚自修各种中间输出就是在这里WA然后一直检查模版TAT 
    			if(++cnt==n-1) break;
    		}
    	}
    	dwn(i,q,1){
    		if(ns[i].d==1) ans[i]=w[query(ns[i].u,ns[i].v)];
    		else{
    			u=ns[i].u,v=ns[i].v,d=ns[i].id;tmp=query(u,v);
    			if(es[d].d<w[tmp]) {
    				cut(tmp,es[tmp-n].u);cut(tmp,es[tmp-n].v);
    				link(u,d+n);link(v,d+n);
    			}
    		}
    	}
    	rep(i,1,q) if(ns[i].d==1) printf("%d
    ",ans[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    JAVA字符串格式化-String.format()的使用
    分布式文件系统MFS(moosefs)实现存储共享(第二版)
    iOS 动画学习
    复制对象(一)copy和mutableCopy方法
    iOS-获取当前网页的 url 和 title 和 html
    排序算法 c实现
    常用正则表达式
    iOS-获取的NSDate date时间与实际相差8个小时解决方案
    网络爬虫基本原理(二)
    网络爬虫基本原理(一)
  • 原文地址:https://www.cnblogs.com/fighting-to-the-end/p/5894148.html
Copyright © 2020-2023  润新知