• 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;
    }
    
    
  • 相关阅读:
    像画笔一样慢慢画出Path的三种方法(补充第四种)
    占位符行为 PlaceHolderBehavior 的实现以及使用
    WPF实现物理效果 拉一个小球
    WPF实现Twitter按钮效果
    WPF自适应可关闭的TabControl 类似浏览器的标签页
    WPF仿百度Echarts人口迁移图
    WPF绘制简单常用的Path
    51Nod 1534 棋子游戏
    数论基础
    Buy a Ticket
  • 原文地址:https://www.cnblogs.com/fruitea/p/12129079.html
Copyright © 2020-2023  润新知