其他分享
首页 > 其他分享> > 洛谷 P1084 疫情控制

洛谷 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