题目描述
题解
二分+判定,问题转化成了在mid的时间里能不能控制疫情。
关键是怎么check。
可以看出让所有的军队尽量向上走一定是最优的。可以倍增求出所有的军队在mid的时间里最多走到哪个点。
对于所有走不到根的军队,它们就只能停在那里了。对于所有走到根之后还有剩余时间的军队,可以继续走到根的别的儿子上,这些军队成为可以调动的军队。
枚举根的每一个儿子,如果这个儿子所代表的子树已经被控制了,即子树中所有走不到根的军队已经可以控制了这个子树,就不用管它。
如果它代表的子树没有被控制(注意这里不包括经过这个子树走到根的点),那么称这个点为需要调入的点。
所有可调动的军队都有一个剩余时间,所有需要调入的点都有一个需要时间(即根到儿子的边的权),将这两种点分别从小到大排序,贪心地分配,就可以达到目的。
需要注意的一点是,所有能走到根的军队一定是从根的某一个儿子走上来的,如果再让这个军队调去这个儿子的话,不能计算时间。具体做法是从小到大排序后,如果当前军队走上来的那个点没有被控制的话,就让这支军队去控制它走上来的那个点,否则的话,让它去控制它能控制的最小的点。
细节不好好想会出错的。
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
#define N 50005
#define sz 16
int n,m,x,y,z,loc[N],cnt; LL Max,ans;
int tot,point[N],nxt[N*2],v[N*2]; LL c[N*2];
int f[N][sz+5]; LL s[N][sz+5];
bool vis[N],leaf,has_res[N];
struct hp
{
int pt,lastp; LL ti,leftime;
bool ctr;
}goal[N],res[N],save[N];
inline void addedge(int x,