先考虑一下合法的 \(k\) 的上界和下界是什么以及如何达到上界和下界,我们找出树的一个重心 \(R\) 并以 \(R\) 为根 dfs 一遍整棵树,那么:
- 下界为 \(\sum(siz_i\bmod 2)\),构造方法是从下往上钦定,对于一个点考虑其所有没有匹配的儿子,如果是偶数个就将它们两两匹配,如果是奇数个就将它们两两匹配,然后剩余的那个与当前节点匹配。
- 上界为 \(\sum siz_i\),方法就是将根节点每个子树看作一种颜色,然后每次从颜色数量最多的两种颜色里各取一个点匹配。
另外,\(k\) 的奇偶性必须与 \(L\) 和 \(R\) 相同,否则也无解。
剩余的情况是否都有解呢?考虑通过构造说明。考虑这样一种思路,我们先假设所有点都与一个颜色与其不同的点匹配(即 \(k\) 达到上界),然后每次我们选择下界对应的构造方案中的两个点 \(x,y\),然后尝试将它们匹配,这样 \(k\) 会减去 \(dep_x+dep_y-\text{dis}(x,y)\),如此下去直到 \(k\) 达到我们想要的值即可。更具体地,对于根节点的每个子树,我们记录下,在下界对应的构造方案中,该子树中的点的匹配情况,然后每次我们取出剩余节点数最多的颜色(目的是为了保证任意时刻剩余部分可以做到“两两匹配且每对匹配点颜色不同),然后取出里面最深的一对匹配点,如果它俩匹配后 \(k\) 的值比我们想要的小,那么我们设 \(u\) 为两点中较深的一者,我们考虑将 \(u\) 与其某个祖先匹配使得匹配后的 \(k\) 刚好是我们想要的值(由于调整后的 \(k\) 值关于另一个匹配点的深度形成的函数为斜率为 \(2\) 的等差数列,且我们的奇偶性是有保证的,所以一定能找到),否则就将它俩匹配。剩余的部分就用达到上界的构造方法即可。
const int MAXN=1e5;
const int INF=0x3f3f3f3f;
int n,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec;ll k;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int mx0[MAXN+5],siz0[MAXN+5],rt;
void dfs0(int x,int f){
siz0[x]=1;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f)continue;dfs0(y,x);
siz0[x]+=siz0[y];chkmax(mx0[x],siz0[y]);
}chkmax(mx0[x],n-siz0[x]);if(mx0[x]<mx0[rt])rt=x;
}
int dep[MAXN+5],siz[MAXN+5],cnt[MAXN+5],fa[MAXN+5];ll L,R;
void dfs1(int x,int f){
siz[x]=1;fa[x]=f;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f)continue;
dep[y]=dep[x]+1;dfs1(y,x);siz[x]+=siz[y];
}
}
bool vis[MAXN+5],die[MAXN+5];
vector<pii>pr[MAXN+5],res;
vector<int>pt[MAXN+5];
void dfs2(int x,int f,int r){
vector<int>vec;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f)continue;
dfs2(y,x,r);if(!vis[y])vec.pb(y);
}
if(vec.size()%2)vec.pb(x),vis[x]=1;
for(int i=0;i<vec.size();i+=2)pr[r].pb(mp(vec[i],vec[i+1]));
}
void dfs3(int x,int f,int r){
if(!die[x])pt[r].pb(x);
for(int e=hd[x];e;e=nxt[e])if(to[e]!=f)dfs3(to[e],x,r);
}
int main(){
scanf("%d%lld",&n,&k);
for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
mx0[0]=INF;dfs0(1,0);dfs1(rt,0);
for(int i=1;i<=n;i++)R+=dep[i],L+=siz[i]&1;
if(k<L||k>R||k%2!=L%2)return puts("NO"),0;
puts("YES");
for(int e=hd[rt];e;e=nxt[e])dfs2(to[e],rt,to[e]);
ll nd=R-k;set<pii>st;
for(int e=hd[rt];e;e=nxt[e]){
int x=to[e];reverse(pr[x].begin(),pr[x].end());
st.insert(mp(cnt[x]=siz[x],x));
}
while(!st.empty()&&nd){
pii p=*st.rbegin();st.erase(st.find(p));
int x=p.se;pii pp=pr[x].back();pr[x].ppb();
int u=pp.fi,v=pp.se;if(dep[u]>dep[v])swap(u,v);
int dlt=dep[u]+dep[v]-((dep[u]==dep[v])?2:1);
if(nd>=dlt)nd-=dlt,die[u]=die[v]=1,st.insert(mp(p.fi-2,x)),res.pb(mp(u,v));
else{
int k=dep[u]-nd/2,w=u;while(k--)w=fa[w];
die[u]=die[w]=1;nd=0;st.insert(mp(p.fi-1-(w!=rt),x));
res.pb(mp(u,w));
}
}
for(int e=hd[rt];e;e=nxt[e])dfs3(to[e],rt,to[e]);
while(!st.empty()){
pii p=*st.rbegin();st.erase(st.find(p));
if(!p.fi)break;
if(p.fi==1&&(st.empty()||(st.rbegin()->fi)==0)){
res.pb(mp(pt[p.se].back(),rt));break;
}
pii pp=*st.rbegin();st.erase(st.find(pp));
res.pb(mp(pt[p.se].back(),pt[pp.se].back()));
pt[p.se].ppb();pt[pp.se].ppb();
st.insert(mp(p.fi-1,p.se));st.insert(mp(pp.fi-1,pp.se));
}
for(pii p:res)printf("%d %d\n",p.fi,p.se);
return 0;
}
/*
6 4
1 2
2 3
2 4
1 5
5 6
*/
标签:Distance,pp,匹配,int,Codeforces,st,fi,Matching,se
From: https://www.cnblogs.com/tzcwk/p/Codeforces-1396E.html