[noip2012]疫情控制

疫情控制这里写链接内容
题目描述

H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点。

H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。

现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。

请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。

输入输出格式

输入格式:
第一行一个整数 n,表示城市个数。

接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。

接下来一行一个整数 m,表示军队个数。

接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎的城市的编号。

输出格式:
共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。

输入输出样例

输入样例#1: 复制
4
1 2 1
1 3 2
3 4 3
2
2 2
输出样例#1: 复制
3
说明

【输入输出样例说明】

第一支军队在 2 号点设立检查点,第二支军队从 2 号点移动到 3 号点设立检查点,所需时间为 3 个小时。

【数据范围】

保证军队不会驻扎在首都。

对于 20%的数据,2≤ n≤ 10;

对于 40%的数据,2 ≤n≤50,0 < w < 10^5;

对于 60%的数据,2 ≤ n≤1000,0 < w <10^6;

对于 80%的数据,2 ≤ n≤10,000;

对于 100%的数据,2≤m≤n≤50,000,0 < w < 10^9。

NOIP 2012 提高组 第二天 第三题

//超恶心-调了两晚上
大体就是 贪心+二分+倍增

以下文字来自litble
1.预处理倍增

我们会发现,离根节点越近的节点,控制的节点更多。所以由贪心的思想,所有的军队都要尽可能地往根节点走。

”往上提“类型问题一般使用倍增优化。
好大的,那么我们可以dfs一遍,将倍增要用的一些值都处理好

2.二分答案

军队可以同时移动,说明我们要控制传染病的时间是军队移动到位时,移动时间最长的军队的移动时间。而我们要求最小值,即要求最大化最小值。

二分答案一般用于求最大化最小值,最小化最大值。

所以就是二分啦,二分一个答案,事情就会更有方向。

3.”上提“军队

使用倍增的方法将军队在二分出的答案限制内尽力往上”提“,不过不可以到根节点。

4.处理剩余路程

如果当前军队可以到达根节点,那么记录一下它的编号和它到达根节点后还可以走的时间rest。如果这个军队i在根节点的子树x中,那么记录一下子树x的符合这个条件的点中,到根节点后剩余路程最短的点。

如果不可以到达,记录它被”提“到的节点被军队设置了检查点。

5.dfs找未被”封死“的子树

如果一个节点建立了检查点或者它的所有子树都设立了检查点,则说明以这个节点为根的子树已经被“封死”。记录根节点的所有子树中,未被“封死”的子树。

6.军队在子树间转移

将我们已经记录好了的可以到根节点的军队按照剩余路程从大到小排序。

将未被“封死”的子树按照到子树到根节点的距离从大到小排序。

然后依次处理未被“封死”的子树要由哪支军队来管辖。

当然离根节点远的军队由剩余路程大的军队来管辖是吼滴啦,不过缀吼滴还是就由本来就在这棵子树上的军队来管辖。所以我们先查看我们事先记录的(在子树x中,可以到达根节点,且到根节点后剩余路程最小的军队)是否被使用,如果被使用,再看当前没有被使用的军队里剩余路程最大的可否到达这棵子树。

这样我们就可以判断当前二分出的答案是否可行了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn = 50000 + 100;
int n,m;
struct edge {
    int u,v,w;
    int next;
}e[maxn << 1];
int head[maxn], tot = 0,cnt = 0;
int val[maxn],vis[maxn],f[maxn][30],p[maxn][30],ans = -1;
int dis[maxn],root[maxn];

int  read() {
    int  x = 0, t = 1;
    char ch = getchar();
    while(ch < '0' || ch >'9'){
        if(ch == '-') t = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * t;
}

void add(int u, int v, int w) {
    e[++tot] = (edge){u,v,w,head[u]};
    head[u] = tot;
}

void dfs(int x,int fa) {
    for(int i = head[x]; i; i = e[i].next) {
        int v = e[i].v;
        if(v != fa) {
            f[v][0] = x;
            p[v][0] = e[i].w;
            if(x == 1) root[v] = v;
            else root[v] = root[x];
			dfs(v,x);
        }
    }
}

void init() {
    for(int j = 1; j <= 17; j++) {
        for(int i = 1; i <= n; i++) {
            f[i][j] = f[f[i][j-1]][j-1];
            p[i][j] = p[i][j-1] + p[f[i][j-1]][j-1];
        }
    }
}

struct chao {
	int u,w;
	bool operator < (const chao b) const {
		return w < b.w;
	}
}du[maxn];
struct bian {
	int u,w;
	bool operator < (const bian b) const {
		return w < b.w;
	}
}que[maxn];

bool dfs_(int x) {
	if(vis[x] == 0 && dis[x] == 1) 		return 1;
	for(int i = head[x]; i; i = e[i].next) {
		int v = e[i].v;
		if(v != f[x][0]) {
			if(vis[x]) vis[v] = vis[x];
			if(dfs_(v)) {
				return 1;
			}
		}
	}
	return 0;
}

bool pd(int mid) {
	memset(vis,0,sizeof(vis));
	memset(du,0,sizeof(du));
	memset(que,0,sizeof(que));
	tot = 0,cnt = 0;
    for(int i = 1; i <= m; i++) {
        int x = val[i],lu = mid;
        for(int j = 17; j >= 0; j--) {
        	if(lu - p[x][j] >= 0 && f[x][j] != 0) {
        		lu -= p[x][j];
        		x = f[x][j];
        	}
        }
        if(x == 1) {
        	du[++tot].u = root[val[i]], du[tot].w = lu;
        }
        else vis[x] = 1;
    }

    for(int i = head[1]; i; i = e[i].next) {
    	int v = e[i].v;
    	if(!vis[v] && dfs_(v)) {
    		que[++cnt].w = e[i].w, que[cnt].u = v;
    	}
    	else vis[v] = 1;
    }    
    sort(du+1,du+1+tot);
    sort(que+1,que+1+cnt);
    int t = 1;
    for(int i = 1; i <= tot; i++) {
    	if(!vis[du[i].u]) vis[du[i].u] = 1;
    	else {
    		while(vis[que[t].u]) t++;
    		if(du[i].w >= que[t].w) vis[que[t++].u] = 1;
    	}
    	while(vis[que[t].u]) t++;
    }
    return t > cnt;
}

int main() {
    n = read();
    for(int i = 1; i < n;i++) {
        int u = read(), v = read(),w = read();
        add(u,v,w);
        add(v,u,w);
        dis[u]++,dis[v]++;
    }
    m = read();
    for(int i = 1; i <= m; i++)	val[i] = read();	
    dfs(1,0);
    init();
    int l = 0, r = 1000000000;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(pd(mid)) {
            ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
    cout<<ans<<endl;
    return 0;
}

posted @ 2017-10-30 22:51  Taunt  阅读(177)  评论(0)    收藏  举报