Luogu2542 [AHOI2005]航线规划

Link

Solution

LCT维护边双的裸题。每次的答案是路径上边双数量-1。

维护边双可以用并查集维护,每次操作就直接作用在边双的代表元素上就行了。因为怕自己漏掉一些(find()),导致没有在代表元素上操作,干脆就丧心病狂地在进入任意函数的时候都(find())一遍(反正复杂度也很低就是了)。当然除了缩点的函数(combine())。还有,似乎涉及到父亲的都需要(find())

另外就是缩点之后代表元素要继承splay根节点的父亲,然后实儿子全都断掉。因为缩点就是把整个splay中的点缩成一个点,所以原本的实边关系都消失,只剩下虚边关系。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define REP(i,a,b) for(int i=(a),ed=(b);i<=ed;++i)
inline int read(){
	register int x=0,f=1;register char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
	while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
	return f?x:-x;
}

const int N=3e4+10,M=1e5+10;
int n,m,t,ans[N],tp;
map<pair<int,int>,int> h;
struct node{int op,x,y;}e[M],q[M];

namespace LinkCutTree{
	int fa[N],ch[N][2],f[N],r[N],s[N];
	inline int find(int x){return f[x]=f[x]==x?f[x]:find(f[x]);}
	inline void pushup(int x){s[x]=s[ch[x][0]]+s[ch[x][1]]+1;}
	inline void pushr(int x){swap(ch[x][0],ch[x][1]),r[x]^=1;}
	inline void pushdown(int x){if(r[x])pushr(ch[x][0]),pushr(ch[x][1]),r[x]=0;}
	inline int getdir(int x){return x==ch[find(fa[x])][1];}
	inline bool noroot(int x){return x==ch[find(fa[x])][0]||x==ch[find(fa[x])][1];}
	inline void rotate(int x){
		x=find(x);int f=find(fa[x]),p=find(fa[f]),k=getdir(x),s=ch[x][!k];
		ch[x][!k]=f;ch[f][k]=s;if(noroot(f))ch[p][getdir(f)]=x;
		fa[f]=x;fa[x]=p;if(s)fa[s]=f;
		pushup(f);
	}
	inline void splay(int x){
		static int stk[N];
		x=find(x);int tp=0,y=x;stk[++tp]=y;
		while(noroot(y))stk[++tp]=y=find(fa[y]);
		while(tp)pushdown(stk[tp--]);
		for(int f=find(fa[x]);noroot(x);rotate(x),f=find(fa[x]))
			if(noroot(f))rotate(getdir(f)==getdir(x)?f:x);
		pushup(x);
	}
	inline void access(int x){
		x=find(x);
		for(int y=0;x;y=x,x=find(fa[x]))
			splay(x),ch[x][1]=y,pushup(x);
	}
	inline void makeroot(int x){
		x=find(x);access(x);splay(x);pushr(x);
	}
	inline int findroot(int x){
		x=find(x);access(x);splay(x);
		while(ch[x][0])pushdown(x),x=ch[x][0];
		splay(x);return x;
	}
	inline void split(int x,int y){
		x=find(x),y=find(y);makeroot(x);access(y);splay(y);
	}
	inline void combine(int x){
		pushdown(x);
		if(ch[x][0])f[find(ch[x][0])]=find(x),combine(ch[x][0]);
		if(ch[x][1])f[find(ch[x][1])]=find(x),combine(ch[x][1]);
	}
	inline void link(int x,int y){
		x=find(x),y=find(y);if(x==y)return;
		makeroot(x);
		if(findroot(y)^x)fa[x]=y;
		else{
			split(x,y);combine(y);
			int t=find(y);
			fa[t]=find(fa[y]);ch[t][0]=ch[t][1]=0;
			pushup(t);
		}
	}
}using namespace LinkCutTree;

int main(){
	n=read(),m=read();
	REP(i,1,m){
		e[i]=(node){0,read(),read()};
		if(e[i].x>e[i].y)swap(e[i].x,e[i].y);
		h[make_pair(e[i].x,e[i].y)]=i;
	}
	while(1){
		int op=read();if(!~op)break;
		q[++t]=(node){op,read(),read()};
		if(q[t].x>q[t].y)swap(q[t].x,q[t].y);
		if(!op)e[h[make_pair(q[t].x,q[t].y)]].op=1;
	}
	REP(i,1,n)f[i]=i;
	REP(i,1,m)if(!e[i].op)link(e[i].x,e[i].y);
	while(t){
		int x=find(q[t].x),y=find(q[t].y);
		if(q[t].op){
			split(x,y);
			ans[++tp]=s[y]-1;
		}
		else link(x,y);
		--t;
	}
	while(tp)printf("%d
",ans[tp--]);
	return 0;
}

原文地址:https://www.cnblogs.com/fruitea/p/12129079.html