洛谷 P1084 疫情控制
作者:互联网
最小化最大值,显然就是个二分。
不难发现一个显而易见的性质:军队只能往上移动。
预处理一下倍增,每次把所有军队都尽量向上移,然后不难推理出一个贪心从而解决。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
inline int read(void){
int res = 0;
char ch = std::getchar();
while(ch < '0' || ch > '9')
ch = std::getchar();
while(ch >= '0' && ch <= '9')
res = res * 10 + ch - 48, ch = std::getchar();
return res;
}
typedef long long ll;
const int MAXN = 5e4 + 19;
struct Edge{
int to, next, dist;
}edge[MAXN << 1];
int head[MAXN], cnt;
inline void add(int from, int to, int dist){
edge[++cnt].to = to;
edge[cnt].dist = dist;
edge[cnt].next = head[from];
head[from] = cnt;
}
int n, m, loc[MAXN];
int dep[MAXN], fa[MAXN][20];
ll dist[MAXN][20];
void dfs(int node, int f){
dep[node] = dep[f] + 1;
fa[node][0] = f;
for(int i = 1; (1 << i) <= dep[node]; ++i)
fa[node][i] = fa[fa[node][i - 1]][i - 1];
for(int i = 1; (1 << i) <= dep[node]; ++i)
dist[node][i] = dist[node][i - 1] + dist[fa[node][i - 1]][i - 1];
for(int i = head[node]; i; i = edge[i].next)
if(edge[i].to != f){
dist[edge[i].to][0] = edge[i].dist;
dfs(edge[i].to, node);
}
}
inline bool cmp_greater(const ll &a, const ll &b){
return a > b;
}
bool has_troop[MAXN];
bool dfs1(int node, int f){
if(has_troop[node])
return true;
int dim = 0;
for(int i = head[node]; i; i = edge[i].next)
if(edge[i].to != f){
++dim;
if(!dfs1(edge[i].to, node))
return false;
}
return dim;
}
bool check(ll t){
static int pos[MAXN];
static ll rest[MAXN], len[MAXN];
static std::vector<ll> troop[MAXN], all, ned;
static bool vist[MAXN];
std::memset(has_troop, 0, sizeof has_troop);
for(int i = head[1]; i; i = edge[i].next)
vist[edge[i].to] = false, troop[edge[i].to].clear(), len[edge[i].to] = edge[i].dist;
for(int i = 1; i <= m; ++i){
rest[i] = t, pos[i] = loc[i];
for(int j = 17; ~j; --j)
if(dep[fa[pos[i]][j]] >= 2 && dist[pos[i]][j] <= rest[i])
rest[i] -= dist[pos[i]][j], pos[i] = fa[pos[i]][j];
if(dep[pos[i]] == 2){
if(rest[i] <= len[pos[i]])
vist[pos[i]] = true;
else
troop[pos[i]].push_back(rest[i] - len[pos[i]]);
}
else
has_troop[pos[i]] = true;
}
for(int i = head[1]; i; i = edge[i].next)
if(!vist[edge[i].to])
vist[edge[i].to] = dfs1(edge[i].to, 1);
all.clear();
for(int i = head[1]; i; i = edge[i].next){
int u = edge[i].to;
if(troop[u].size())
std::sort(troop[u].begin(), troop[u].end(), cmp_greater);
if(!vist[u] && troop[u].size() && troop[u][troop[u].size() - 1] <= len[u])
troop[u].pop_back(), vist[u] = true;
for(auto j : troop[u])
all.push_back(j);
}
ned.clear();
for(int i = head[1]; i; i = edge[i].next)
if(!vist[edge[i].to])
ned.push_back(edge[i].dist);
if(all.size() < ned.size())
return false;
if(all.size())
std::sort(all.begin(), all.end());
if(ned.size())
std::sort(ned.begin(), ned.end());
while(ned.size()){
if(all[all.size() - 1] >= ned[ned.size() - 1])
all.pop_back(), ned.pop_back();
else
return false;
}
return true;
}
ll bound(ll l, ll r){
while(l < r){
ll mid = (l + r) >> 1;
if(check(mid))
r = mid;
else
l = mid + 1;
}
if(check(l))
return l;
else
return -1;
}
int main(){
n = read();
ll limit = 0ll;
for(int i = 1; i < n; ++i){
int u = read(), v = read(), w = read();
add(u, v, w);
add(v, u, w);
limit += w;
}
dfs(1, 0);
m = read();
for(int i = 1; i <= m; ++i)
loc[i] = read();
std::printf("%lld\n", bound(0, limit));
return 0;
}
标签:ch,洛谷,疫情,int,ll,read,P1084,edge,return 来源: https://www.cnblogs.com/feiko/p/13110291.html