• 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;
    }
    
    
  • 相关阅读:
    LeetCode Count of Range Sum
    LeetCode 158. Read N Characters Given Read4 II
    LeetCode 157. Read N Characters Given Read4
    LeetCode 317. Shortest Distance from All Buildings
    LeetCode Smallest Rectangle Enclosing Black Pixels
    LeetCode 315. Count of Smaller Numbers After Self
    LeetCode 332. Reconstruct Itinerary
    LeetCode 310. Minimum Height Trees
    LeetCode 163. Missing Ranges
    LeetCode Verify Preorder Serialization of a Binary Tree
  • 原文地址:https://www.cnblogs.com/fruitea/p/12129079.html
Copyright © 2020-2023  润新知