題面
題目大意:給定兩棵樹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; }