首页 > 其他分享 >Codeforces 1396E - Distance Matching

Codeforces 1396E - Distance Matching

时间:2023-07-14 10:55:08浏览次数:40  
标签:Distance pp 匹配 int Codeforces st fi Matching se

先考虑一下合法的 \(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

相关文章

  • Codeforces 1740H - MEX Tree Manipulation
    首先发现一个性质,那就是每个点的点权是\(\logn\)级别的。因为假设要造出一个点权为\(i\)的点至少需要大小为\(mn_i\)的子树,那么显然有\(mn_i=\sum\limits_{j=0}^{i-1}mn_j+1\),即\(mn_i=2^i\)。由于点权不是很大,因此我们很容易地往变换复合的角度思考。将整棵树进行轻重......
  • Codeforces Round #882 (Div. 2) A-D
    比赛链接A代码#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;inta[107];intf[107];boolsolve(){intn,k;cin>>n>>k;for(inti=1;i<=n;i++)cin>>a[i];for(inti=1;i<=n-1;......
  • codeforces1283F
    题目链接sol:根一定是第一个,然后不太会,去看了洛谷题解题解#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;typedefpair<int,int>pii;#definefifirst#definesesecond#definefz1(i,n)for((i)=1;(i)<=(n);(i)++)#definefd1(i,n)for((i)......
  • Educational Codeforces Round 151 (Rated for Div. 2)
    D.RatingSystem题目大意玩家的初始积分为0,该玩家连续进行\(n\)场比赛,每场比赛可升高或降低玩家的积分(\(a_i\))。你可以设置一个\(k\)值,比赛过程中玩家的积分不会低于\(k\)(若有一场比赛会使玩家的积分低于\(k\),比赛后玩家的积分会被强制变为\(k\))。找到一个\(k\),使经过\(n\)......
  • codeforces1311E
    题目链接sol:先建一条链,然后把下面的点一个个往上面移,优先移到最上面,如果上面满了就往下一层,知道刚刚好凑满距离,如果最后不能移了就说明不能凑出给定的距离#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;typedefpair<int,int>pii;#definefifir......
  • Codeforces Round 884 (Div. 1 + Div. 2)
    Preface究极坐牢场,比赛降智导致签到签挂,本来秒出的D写错一个极其傻逼的地方浪费半小时然后后面两个小时坐牢想E和F1,但可惜并没有看出E的性质,被狠狠地薄纱虽然说实话后面有点困了,但应该不至于写不出这个E的,只能说最近的状态真是堪忧啊A.SubtractionGame首先若\(a\ne1\)则......
  • Codeforces Round 884 (Div. 1 + Div. 2)
    A.SubtractionGame答案就是a+b此时后手必胜因为无论怎么操作后手都可保证自己取的时候一次全部取完#include<bits/stdc++.h>usingnamespacestd;voidsolve(){inta,b;cin>>a>>b;cout<<a+b<<"\n";return;}intmain(){......
  • codeforces-817 D. Imbalanced Array(单调栈)
    题意:求数组中每个连续子序列的的最大值-最小值之和。思路:题意可以理解为加上每一个序列的最大值,减去每一个序列的最小值。每个数都可以作为某一连续子序列的最大值和最小值,所以可以枚举每一个数作为最值的区间,暴力枚举时间复杂度过高,所以利用单调栈找出每个数左边或右边第一个比......
  • Codeforces Round 871 (Div. 4) ABCDEF
    很久没写题目了,划点水题A.LoveStory#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;typedefpair<LL,LL>PII;constLLMAXN=1e18;constLLN=1e6,M=4002;constLLmod=1e9+7;intmain(){//cin.tie(0);cout.tie(0);ios......
  • 「解题报告」Codeforces Round #884 (Div. 1 + Div. 2) Editorial
    比赛地址:Dashboard-CodeforcesRound884(Div.1+Div.2)-Codeforces个人评价:这场是构造专场!A.SubtractionGameProblem-A-Codeforces有一堆石子(应该是石子),每次只能拿走\(a\)块或者\(b\)块,最先不能移动的人输,构造一个数\(n\),使得先手必输。两种构造方法:......