记录编号 130597 评测结果 AAAAAAAAAA
题目名称 [NOIP 2012]疫情控制 最终得分 100
用户昵称 GravatarAsm.Def 是否通过 通过
代码语言 C++ 运行时间 0.154 s
提交时间 2014-10-22 19:44:05 内存使用 2.22 MiB
显示代码纯文本
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <set>
using namespace std;

#if defined DEBUG
FILE *in = fopen("test", "r");
#define out stdout
#else
FILE *in = fopen("blockade.in","r");
FILE *out = fopen("blockade.out","w");
#endif
/*==============================================*/
#define maxn ((int)5e4 + 5)
#define pb push_back
#define iter vector<edge>::iterator

struct edge{
	int to, w;
	edge(int T,int W):to(T),w(W){}
};

struct army{
	int restT, newT, loc;
}temp[maxn];
int tempcnt;

void getint(int &k){
	char c;
	while(!isdigit(c))c = fgetc(in);
	k = c - '0';
	while(isdigit(c = fgetc(in)))k = k * 10 + c - '0';
}

int n, m, L = 0, R = 0;
int dis[maxn]={0}, root[maxn], pre[maxn], armyloc[maxn];
vector<edge> adj[maxn];

void DFS(int k){//预处理dis,root和pre
	iter it;
	for(it = adj[k].begin();it < adj[k].end();++it){
		if(it->to == pre[k])continue;
		dis[it->to] = dis[k] + it->w;
		root[it->to] = root[k];
		pre[it->to] = k;
		DFS(it->to);
	}
}

bool operator <(const edge&a,const edge&b){
	return dis[a.to] < dis[b.to];
}

bool init(){//0: no answer
	int i,u,v,w;
	getint(n);
	for(i = 1;i < n;++i){
		getint(u),getint(v),getint(w);
		adj[u].pb(edge(v,w));
		adj[v].pb(edge(u,w));
	}
	getint(m);
	if(m < (int)adj[1].size())return 0;
	iter it = adj[1].begin();
	for(;it < adj[1].end();++it){
		root[it->to] = it->to;
		pre[it->to] = 1;
		dis[it->to] = it->w;
		DFS(it->to);
	}
	for(i = 0;i < m;++i){getint(armyloc[i]);R = max(R, dis[armyloc[i]]);}
	sort(adj[1].begin(), adj[1].end());
	R += dis[(adj[1].end()-1)->to];
	return 1;
}

bool Acmp(const army&a, const army&b){//按到达首都后的剩余时间排序
	return a.newT < b.newT;
}

bool check(int k){
	int i,j;
	iter it;
	tempcnt = 0;
	bool ctrled[maxn] = {0};
	for(i = 0;i < m;++i){//贪心上行
		j = armyloc[i];
		while(pre[j] != 1 && dis[armyloc[i]] - dis[pre[j]] <= k)
			j = pre[j];
		if(pre[j] != 1){
			while(pre[j] != 1){//j到root[j]是否是一条链,如果是则直接设置ctrled
				if((int)adj[pre[j]].size() > 2)break;
				j = pre[j];
			}
			if(pre[j] == 1)ctrled[j] = 1;
		}
		else{
			temp[tempcnt].newT = k - dis[armyloc[i]];
			temp[tempcnt].loc = j;
			temp[tempcnt++].restT = k - dis[armyloc[i]] + dis[j];
		}
	}
	multiset<int> Free;
	multiset<int>::iterator it_S;
	sort(temp, temp + tempcnt, Acmp);
	for(i = 0;i < tempcnt;++i){//是否要暂时到首都部署(Free维护要到首都的军队的剩余时间)
		int newT = temp[i].restT - dis[temp[i].loc];
		if(!ctrled[temp[i].loc]){
			if(!Free.empty()){//用temp[i]替换在首都的更无用的军队
				it_S = Free.lower_bound(dis[temp[i].loc]);
				if(it_S != Free.end() && *it_S < temp[i].newT){
					Free.erase(it_S);
					Free.insert(temp[i].newT);
				}
			}
			ctrled[temp[i].loc] = 1;
		}
		else if(newT >= 0)//已被更无用的军队控制,果断来到首都部署
			Free.insert(temp[i].newT), temp[i].restT = newT;
	}
	for(it_S = Free.begin(),it = adj[1].begin();it < adj[1].end();++it){
		if(ctrled[it->to])continue;
		while(it_S != Free.end() && *it_S < it->w)++it_S;
		if(it_S == Free.end())return 0;
		++it_S;
	}
	return 1;
}

int main(){
	int k;
	if(!init()){fprintf(out,"-1\n");return 0;}
	while(L <= R){//二分查找
		k = (L >> 1) + (R >> 1) + (L & R & 1);
		if(check(k))R = k - 1;
		else L = k + 1;
	}
	fprintf(out,"%d\n",L);
	return 0;
}