暑假模拟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\) 即可。(代码实现细节有点多)我们记 \(maxn_u\) 为在 \(u\) 的子树中,不在 \(Delov\) 覆盖范围内的节点与 \(u\) 的最大距离, \(minn_u\) 为在 \(u\) 的子树中,\(Delov\) 与 \(u\) 的最小距离,\(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;
}
剩下部分先省略。