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\n",w[u]+sm[c[lca][1]]); 
    else printf("%d\n",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\n",max(w[u],mx[c[lca][1]])); 
    else printf("%d\n",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\n",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\n",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\n",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\n",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\n",ans[i]);
	return 0;
}

  

posted @ 2016-09-21 21:01  BBChq  阅读(246)  评论(0编辑  收藏  举报