CF1452G
Posted chasedeath
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1452G相关的知识,希望对你有一定的参考价值。
CF1452G - Game On Tree
题目大意
A和B在树上Van游戏,每个人操作一些点
A操作一个点\\(i\\),B操作一个点集\\(a_j\\)
每轮A,B分别进行操作,可以对于自己的所有点任意移动1步或0步
在某一轮,当A的点碰到B的点时游戏结束
A希望尽量迟结束,B希望尽量早结束
给定B的初始点集\\(a_j\\),对于A的每个初始点\\(i\\)判断多少轮结束
分析
由于B的操作显然是不停向A收缩直到碰到
那么可以广搜求出每个点原地不动时被B干掉的时间\\(F_i\\)
那么考虑A的移动过程,每一步可以到达一个点\\(u\\)
必须满足在第\\(i\\)步所在的点\\(u\\),\\(F_u>i\\),否则结束游戏
对于初始节点\\(u\\),不妨设最终结束的节点为\\(t\\),我们希望一路跑到\\(t\\)然后站住不动,此时答案就是\\(F_t\\)
而实际上,任何一个点\\(u\\)能够跑到\\(t\\),等价于\\(dis(u,t)<F_t\\)
Proof:
由最短路三角不等式可知
\\(\\forall (u,v)\\in Tree, dis_{v}-1\\leq dis_u\\leq dis_{v}+1\\)
即\\(dis_e\\)在树的路径上连续变化,不妨设移动路径为\\(p_i,i\\in[1,k],p_k=t,k\\leq F_t\\)
若能在\\(F_t-1\\)的时间内到达\\(p_k\\),那么必然能在\\(F_t-2\\)的时间内到达\\(p_{k-1}\\)
进而归纳得到
那么问题变成了,对于每个点\\(u\\),向周围\\(F_u-1\\)范围内的点对于\\(F_u\\)取\\(\\max\\)
容易点分治处理,复杂度为\\(O(n\\log n)\\)
const int N=2e5+10,INF=1e9+10;
int n,F[N],A[N];
vector <int> G[N];
queue <int> que;
int mi,rt,sz[N],vis[N];
void FindRt(int n,int u,int f){
int ma=0; sz[u]=1;
for(int v:G[u]) if(!vis[v] && v!=f) {
FindRt(n,v,u),sz[u]+=sz[v];
cmax(ma,sz[v]);
}
cmax(ma,n-sz[u]);
if(mi>ma) mi=ma,rt=u;
}
int dep[N],id[N],c,s[N];
void dfs(int u,int f){
id[++c]=u;
for(int v:G[u]) if(v!=f && !vis[v]) {
dep[v]=dep[u]+1;
dfs(v,u);
}
}
void Div(int n,int u){
mi=1e9,FindRt(n,u,0),u=rt,vis[u]=1;
c=0,dep[u]=0,dfs(u,0);
rep(i,0,c) s[i]=0;
rep(i,1,c) {
int u=id[i];
if(F[u]>dep[u]) cmax(s[min(c,F[u]-1-dep[u])],F[u]);
}
drep(i,c-1,0) cmax(s[i],s[i+1]);
rep(i,1,c) cmax(A[id[i]],s[dep[id[i]]]);
for(int v:G[u]) if(!vis[v]) {
if(sz[v]>sz[u]) sz[v]=n-sz[u];
Div(sz[v],v);
}
}
int main(){
rep(i,2,n=rd()){
int u=rd(),v=rd();
G[u].pb(v),G[v].pb(u);
}
rep(i,1,n) F[i]=-1;
rep(i,1,rd()) {
int x=rd();
F[x]=0,que.push(x);
}
while(!que.empty()) {
int u=que.front(); que.pop();
for(int v:G[u]) if(F[v]==-1)
F[v]=F[u]+1,que.push(v);
}
Div(n,1);
rep(i,1,n) printf("%d ",A[i]);
}
以上是关于CF1452G的主要内容,如果未能解决你的问题,请参考以下文章