题面
题目大意:给定两棵树T1和T2,咱们称T1中的一条边\(e\)和T2中的一条边\(f\)匹配
当且仅当:T1-\(e\)+\(f\)是棵树。
求这个二分图的最大匹配。
\(n\)<=2.5e5c++
题解:
先大力猜一波结论:这个二分图存在完美匹配。
证实:
首先须要证实这么一个东西:
在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)\)git
代码:spa
#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",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\n",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\n",b,f[b][0],u,v); ma[b]=a; } } return 0; }