记录编号 304162 评测结果 AAAAAAAAAA
题目名称 [NOIP 2012]疫情控制 最终得分 100
用户昵称 GravatarFmuckss 是否通过 通过
代码语言 C++ 运行时间 0.920 s
提交时间 2016-09-07 18:00:26 内存使用 13.52 MiB
显示代码纯文本
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int inf = 2e9;
const int maxn = 5e4 + 10;
const int root = 1;


#define is_num(x) (x <= '9' and x >= '0')
int get_num() {
	char tmp = getchar();
	int res = 0;
	while(not is_num(tmp)) tmp = getchar();
	while(    is_num(tmp)) {
		res = (res << 3) + (res << 1) + (tmp - '0');
		tmp = getchar(); 
	}
	return res;
}


struct Edge {
	int to, ne, v;
	Edge() {}
	Edge(int to_, int ne_, int v_) { to = to_, ne = ne_, v = v_; }
}e[maxn << 1];
int head[maxn], ecnt;
inline void add_edge(int fr, int to, int v) {
	e[++ecnt] = Edge(to, head[fr], v), head[fr] = ecnt;
	e[++ecnt] = Edge(fr, head[to], v), head[to] = ecnt;
}


struct Node {
	int de, pos;
	Node() {}
	Node(int de_, int pos_) { de = de_, pos = pos_; }
	
	bool operator < (const Node &b) const { return de < b.de; }
}ns[maxn];


struct Army {
	int pos, dis;
	bool use;
	Army() {}
	Army(int pos_, int dis_) { pos = pos_, dis = dis_, use = false; }
	
	bool operator < (const Army &b) const { return dis < b.dis; }
}as[maxn];


int mul_fa[maxn][17];
LL mul_dis[maxn][17];
int deep[maxn];
LL max_dis;
int n, m;


void get_mul(int now) {
	ns[now] = Node(deep[now], now);
	for(int i = 1; i <= 16; i++) {
		if(deep[now] < 1 << i) {
			mul_dis[now][i] = inf;
			continue;
		}
		
		int now_fa = mul_fa[now][i - 1];
		mul_fa[now][i] = mul_fa[now_fa][i - 1];
		mul_dis[now][i] = mul_dis[now_fa][i - 1] + mul_dis[now][i - 1];
		max_dis = max(max_dis, mul_dis[now][i]); 
	}
	
	for(int i = head[now]; i; i = e[i].ne) {
		int to = e[i].to;
		if(deep[to] or to == root) continue;
		
		deep[to] = deep[now] + 1;
		mul_fa[to][0] = now;
		mul_dis[to][0] = e[i].v;
		
		get_mul(to);
	}
}


Node un_c[maxn]; // uncontroled dis
int uc_top;
Army re_a[maxn]; // army left dis
int ra_top;
bool is_c[maxn]; // is controled 


inline LL query_dis(int now, int delta) { // 到往上delta层的父节点的距离 
	LL dis = 0;
	for(int i = 0; i <= 16; i++) {
		if(delta & (1 << i))
			dis += mul_dis[now][i], now = mul_fa[now][i];
	}
	return dis;
}


inline int query_fa(int now, int delta) { // 向上delta层 
	for(int i = 0; i <= 16; i++) if(delta & (1 << i)) now = mul_fa[now][i];
	return now;
}


inline bool check(int lim) {
	memset(is_c, 0, sizeof(is_c));

	uc_top = ra_top = 0;
	
	for(int i = 1; i <= m; i++) {
		int now = as[i].pos; // 军队开始位置 
		
		int l = 0, r = deep[now], mid, ans;
		LL dis;
		while(l + 1 < r) {
			mid = (l + r) >> 1;
			
			dis = query_dis(now, mid); 
			
			if(dis <= lim) l = mid; //找到小于限制的最大距离 
			else r = mid - 1;
		}
		
		if((dis = query_dis(now, r)) <= lim) ans = r;
		else if((dis = query_dis(now, r - 1)) <= lim) ans = r - 1;
		else dis = query_dis(now, l), ans = l;
		
		if(ans == deep[now]) { // 如果能到达根节点 
			int re_top = query_fa(now, deep[now] - 1); // 最浅的第二层节点 
			re_a[++ra_top] = Army(re_top, lim - dis);
		} else { // 在之前某一节点停止 
			int tar = query_fa(now, ans);
			is_c[tar] = true;
		}
	}
	
	for(int i = n; i >= 1; i--) {
		int now = ns[i].pos, fa;
		if(now == root) continue;
		
		bool son_st = false;
		if(not is_c[now]) {
			is_c[now] = true;
			
			for(int j = head[now]; j; j = e[j].ne) {
				if(e[j].to != mul_fa[now][0]) {
					son_st = true;
					if(not is_c[e[j].to]) is_c[now] = false;
				}
			}
			
			if(not son_st) is_c[now] = false;
		}
		
		if(deep[now] == 1 and not is_c[now]) {
			fa = query_fa(now, deep[now] - 1);
			un_c[++uc_top] = Node(mul_dis[now][0], fa);
		}
	}
	
	if(uc_top > ra_top) return false;
	else {
		sort(un_c + 1, un_c + uc_top + 1);
		sort(re_a + 1, re_a + ra_top + 1);
		
		int j = 1;
		for(int i = 1; i <= ra_top; i++) {
			while(is_c[un_c[j].pos]) j++;
			if(not is_c[re_a[i].pos]) is_c[re_a[i].pos] = true;
			else if(un_c[j].de <= re_a[i].dis and not is_c[un_c[j].pos]) {
				is_c[un_c[j].pos] = true;
				j++;
			}
		}
		
		for(int i = 1; i <= uc_top; i++) {
			if(is_c[un_c[i].pos]) continue;
			return false;
		}
		return true;
	}
}


inline void read() {
	n = get_num();
	int fr, to, v;
	for(int i = 1; i <= n - 1; i++) {
		fr = get_num();
		to = get_num();
		v = get_num();
		
		add_edge(fr, to, v);
	}
	
	m = get_num();
	for(int i = 1; i <= m; i++) {
		int pos = get_num();
		as[i].pos = pos;
	}
}


inline void solve() {
	get_mul(root);
	sort(ns + 1, ns + n + 1);
	LL l = 0, r = inf, mid, ans;
	
	check(10);
	
	while(l + 1 < r) {
		mid = (l + r) >> 1;
		
		if(check(mid)) r = mid;
		else l = mid + 1;
	}
	
//	printf("l = %lld r = %lld\n", l, r);
	if(check(l)) ans = l;
	else if(check(l + 1)) ans = l + 1;
	else ans = r;
	
	printf("%lld\n", ans == inf ? -1 : ans);
}


int main() {
	freopen("blockade.in", "r", stdin);
	freopen("blockade.out", "w", stdout);
	read();
	solve();
	return 0;
}