CF1284F New Year and Social Network

题面
题目大意:给定两棵树T1和T2,我们称T1中的一条边(e)和T2中的一条边(f)匹配
当且仅当:T1-(e)+(f)是棵树。
求这个二分图的最大匹配。
(n)<=2.5e5

题解:
先大力猜一波结论:这个二分图存在完美匹配。
证明:
首先需要证明这么一个东西:
在T1中任选一条不与T2的边重合的边(e),一定存在T2中的与T1的边不重合的边(f)满足T1-(e)+(f)和T2-(f)+(e)都是一棵树。
首先将(e)加到T2上,那么就形成了一个环。我们要选的(f)边就需要在这个环中选出。
我们将环里的每个点编号为1或2,表示它们分别属于T1-(e)的两个连通块。
那么由于e两边的编号不同,这个环中就永远存在一条1-2的边(f),联通T1。
由此,我们得到了一个O((n^2))的做法。
考虑如何缩减时间复杂度。
因为我们的构造是在改动T2,而T1不能变。而这些找边的操作很难在小于线性的时间内作出。
不难想到选定T2中的边,找T1中满足条件的点。至于如何维护T1的边是否可用,可以拿并查集来维护。
考虑从T2的叶子结点开始考虑。设当前的叶子结点为(u),这条边连向的点是(v)
我们求出(u),(v)在T1中的(lca)(u)所在并查集(连通块)的深度最小的节点(a)
(dep[a]>dep[lca]),我们就选择a和它的father这条边连起来;否则,通过倍增找出(v)(lca)上的一条未使用的且深度最小的边,连起来。
如此操作n-1次即可。
时间复杂度:(O(nlogn))

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
	res=0;register D g=1;register char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')g=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		res=(res<<3)+(res<<1)+(ch^48);
		ch=getchar();
	}
	res*=g;
}
vector<int>e[303000],t[303000];
int n,m,X,Y,lg[303000],dep[303000],f[303000][21],du[303000],ma[303000],vis[303000];
queue<int>q;
I D_1(int x,int fa,int depth){
	dep[x]=depth;f[x][0]=fa;
	F(i,1,lg[dep[x]])f[x][i]=f[f[x][i-1]][i-1];
	for(auto d:e[x]){
		if(d==fa)continue;
		D_1(d,x,depth+1);
	}
}
IN ques_lca(int x,int y){
	if(dep[x]>dep[y])swap(x,y);
	re det=dep[y]-dep[x];
	F(i,0,lg[det])if((det>>i)&1)y=f[y][i];
	if(x==y)return x;
	FOR(i,17,0){
		if(f[x][i]&&f[y][i]&&f[x][i]^f[y][i])x=f[x][i],y=f[y][i];
	}
	return f[x][0];
}
IN find(int x){return ma[x]==x?x:ma[x]=find(ma[x]);}
I merge(int x,int y){
	x=find(x);y=find(y);if(x==y)return;ma[x]=y;
}
int main(){
	read(n);
	F(i,1,n-1){read(X);read(Y);e[X].emplace_back(Y);e[Y].emplace_back(X);}
	F(i,1,n-1){read(X);read(Y);t[X].emplace_back(Y);t[Y].emplace_back(X);du[X]++;du[Y]++;}
	lg[0]=-1;F(i,1,n)lg[i]=lg[i>>1]+1,ma[i]=i;
	D_1(1,0,1);
	F(i,1,n)if(du[i]==1)q.emplace(i);
	printf("%d
",n-1);
	while(q.size()>1){
		re u=q.front(),v;q.pop();vis[u]=1;
		for(auto d:t[u])if(!vis[d]){
			v=d;du[d]--;
			if(du[d]==1)q.emplace(d);
			break;
		}
		re lca=ques_lca(u,v),a,b;
		a=find(u);
		if(dep[a]>dep[lca]){
			b=f[a][0];printf("%d %d %d %d
",a,b,u,v);
			ma[a]=find(b);
		}
		else{
			b=v;
			FOR(i,17,0)if(dep[f[b][i]]>dep[lca]&&find(f[b][i])!=a)b=f[b][i];
			printf("%d %d %d %d
",b,f[b][0],u,v);
			ma[b]=a;
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Purple-wzy/p/13184955.html