暑假模拟7

暑假模拟7

Permutations & Primes

比较简单的构造题,容易发现所选区间只有包含1才可能产生贡献,此时考虑将2,3放在两边,1放在中间,其他数字不重要。构造方法正确性显然。注意 n=1,2 的情况。

树上游戏

Description

这一天,Delov 在和他的 npy 们在树上做游戏,他的 npy 们喜欢不同的位置,所以每个树节点上都有他的 npy,她们都希望 Delov 离自己近一些,否则就会不高兴。具体来讲,Delov 所在节点离某个 npy 所在节点的树上路径长度即为该节点 npy 的不满意度。
Delov 希望能够让所有 npy 的不满意度的最大值最小,而且,作为时间管理大师, Delov 拥有分身术,也就是说,他能同时存在于 k 个节点,对 npy 来说她们会以离自己最近的 Delov 计算不满意度。

Delov 想知道所有 npy 的不满意度的最大值的最小值是多少,并把问题抛给你。

分析

赛时狂调不止,心态炸裂,还没调完,最后一秒没交上。

二分答案的做法比较好想。检验一个答案是否合法,考虑一种贪心的想法,从叶子节点开始,每个 Delov 尽可能靠上放置,但要保证最远距离不超过二分的答案,最后统计最少需要多少 Delov 即可。(代码实现细节有点多)我们记 maxnu 为在 u 的子树中,不在 Delov 覆盖范围内的节点与 u 的最大距离, minnu 为在 u 的子树中,Delovu 的最小距离,DFS 进行转移。注意一些问题,例如判断子树内是否有 Delov ,当遍历到根节点时,注意判断距离,等等。其实是我不记得了

Code

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
int n,m,cnt,head[N],a,b,num;
struct edge{
	int to,nxt;
}e[N<<1];
int depth[N],son[N];
bool last[N],pd[N];
int maxn[N],minn[N];
void add(int u,int v){
	cnt++;
	e[cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
void dfs1(int u,int f){
	depth[u]=depth[f]+1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==f)continue;
		dfs1(v,u);
		son[u]++;
	}
}
void dfs(int u,int f,int k){
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==f)continue;
		dfs(v,u,k);
		minn[u]=min(minn[u],minn[v]+1);
	}
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==f)continue;
		if(maxn[v]+minn[u]+1>k){
			if(maxn[v]+1>=k){
				num++;
				minn[u]=0;
				maxn[u]=-1;
				return ;
			}
		}
		if(u==1&&minn[u]+maxn[u]>k){
			num++;
			return ;
		}
		if(maxn[v]+minn[u]+1>k){
			maxn[u]=max(maxn[u],maxn[v]+1);
		}
		else if(maxn[v]==-1){
			maxn[u]=max(maxn[u],0);
		}
	}
	if(maxn[u]==0&&minn[u]<=k)maxn[u]=-1;
	if(u==1&&minn[u]+maxn[u]>k){
		num++;
		return ;
	}
}
bool check(int x){
	num=0;
	memset(maxn,0,sizeof(maxn));
	memset(minn,0x3f,sizeof(minn));
	dfs(1,1,x);
	if(num<=m)return 1;
	else return 0;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++){
		scanf("%d%d",&a,&b);
		add(a,b);
		add(b,a);
	}
	dfs1(1,1);
	int l=1,r=n-1;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;
}

剩下部分先省略。

posted @   Abnormal123  阅读(18)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示