noip2012 疫情控制
【问题描述】
H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点。
H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。
现在,在H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
【输入】 输入文件名为blockade.in。
第一行一个整数n,表示城市个数。
接下来的n-1行,每行3个整数,u、v、w,每两个整数之间用一个空格隔开,表示从城市u到城市v有一条长为w的道路。数据保证输入的是一棵树,且根节点编号为1。
接下来一行一个整数m,表示军队个数。
接下来一行m个整数,每两个整数之间用一个空格隔开,分别表示这m个军队所驻扎的城市的编号。
【输出】 输出文件为blockade.out。
共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。
【输入输出样例】
blockade.in
4
1 2 1
1 3 2
3 4 3
2
2 2
blockade.out
3
【输入输出样例说明】
第一支军队在2号点设立检查点,第二支军队从2号点移动到3号点设立检查点,所需时间为3个小时。
【数据范围】
保证军队不会驻扎在首都。
对于20%的数据,2≤ n≤ 10;
对于40%的数据,2 ≤n≤50,0<w <105; 对于60%的数据,2 ≤ n≤1000,0<w <106; 对于80%的数据,2 ≤ n≤10,000;
对于100%的数据,2≤m≤n≤50,000,0<w <109。
/*
说一下这个题目的思考过程,首先,你要求一个最小控制的时间,在这一段时间内军队要不停的走,走到哪里与时间是有关的,而能否控制又与走到哪里有关,于是一个很自然的想法就是二分。于是问题变成了给定一个时间,检验在这些时间内是否能够控制所以节点
怎么检验?我们观察到一个事实,给你一些时间,你肯定要尽量往上走,越往上控制的路径就越多,这个走的过程我们用一个倍增的办法来处理。
由于根节点不能建立检查点,如果继续走肯定在往下走一步,那么是往下走还是停在原来的根节点的儿子上?在根节点怎么进行军队的分配?
考虑贪心处理,首先,如果确定一些军队是要去往下走,对于一个没有被控制的根子节点来说,一定是让剩余时间卡的最紧的人去处理他,有了这个思路再去想谁调到根上,谁留在原来的根子节点上,对应子如果已经被控制,一定要往根上跑,如果没有控制再讨论。如果我去了回不来,有可能别人也管不了,而他自己可能排不上用场,最优解可能减小,如果我去了可以回来,这个点在我分配的时候肯定会控制住,而且可能会用一个比较小的来控制使解更优
代码比较长,注意一些细节,我在网上找了很多题解都是90分,可能卡常吧,不管了
*/
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define fd(i,l,r) for(int i = r;i >= l;i--)
#define gfo(i,l,r) for(int i = l;i < r;i++)
#define gfd(i,l,r) for(int i = r;i > l;i--)
using namespace std;
const int maxn = ;
ll read(){
ll x=,f=;
char ch=getchar();
while(!(ch>=''&&ch<='')){if(ch=='-')f=-;ch=getchar();};
while(ch>=''&&ch<=''){x=x*+(ch-'');ch=getchar();};
return x*f;
}
struct edge{
int v;
int nxt;
ll w;
}e[maxn];
struct dat{
int pos;
ll rec;
};
int n,m;
int head[maxn],cnt,fa[maxn][];
ll fa_d[maxn][],d_son[maxn],tot;
int tr[maxn],frm_son[maxn];
ll frm_d[maxn];
bool is_son[maxn],vis_now[maxn];
vector<ll> jd;
vector<int> zq;
vector<dat> dd;
void ins(int u,int v,ll w){
cnt++;
e[cnt].v = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt;
}
void dfs(int x,int rec){
if(rec) frm_son[x] = rec;
int to,lg = ,j = x;
while(fa[x][lg] && fa[fa[x][lg]][lg]){
fa[x][lg+] = fa[fa[x][lg]][lg];
fa_d[x][lg+] = fa_d[x][lg] + fa_d[fa[x][lg]][lg];
lg++;
}
for(int i = head[x];i;i = e[i].nxt){
to = e[i].v;
if(to == fa[x][]) continue;
fa[to][] = x;
if(x == ){
frm_d[to] = e[i].w;
is_son[to] = true;
rec = to;
}
fa_d[to][] = e[i].w;
dfs(to,rec);
}
}
bool dfs2(int x){
if(vis_now[x]) return true;
bool have_son = false;
for(int i = head[x];i;i = e[i].nxt){
if(e[i].v == fa[x][]) continue;
have_son = true;
if(!dfs2(e[i].v)) return false;
}
if(!have_son) return false;
return true;
}
bool cmp(int a,int b){
return frm_d[a] < frm_d[b];
}
bool check(ll t){
memset(vis_now,,sizeof(vis_now));
dd.clear();
jd.clear();
zq.clear();
int now,lg;
ll tmp;
dat gg;
fo(i,,m){
now = tr[i];
lg = tmp = ;
while(lg >= ){
if(fa[now][lg]&&tmp + fa_d[now][lg] <= t){
tmp += fa_d[now][lg];
now = fa[now][lg];
lg++;
}else lg--;
}
if(is_son[now]){
vis_now[now] = true;
}else if(now == && tmp + frm_d[frm_son[tr[i]]] > t){
gg.pos = frm_son[tr[i]];
gg.rec = t-tmp;
dd.push_back(gg);
}else if(now == ){
jd.push_back(t-tmp);
}else{
vis_now[now] = true;
}
}
for(int i = head[];i;i = e[i].nxt){
if(dfs2(e[i].v))vis_now[e[i].v] = true;
}
for(int i = ;i < dd.size();i++){
if(!vis_now[dd[i].pos]) vis_now[dd[i].pos] = true;
else jd.push_back(dd[i].rec);
}
for(int i = head[];i;i = e[i].nxt){
if(!vis_now[e[i].v]) zq.push_back(e[i].v);
}
sort(jd.begin(),jd.end());
sort(zq.begin(),zq.end(),cmp);
int now_jd = ,now_zq = ;
if(jd.size() < zq.size()) return false;
while(now_zq < zq.size()){
if(now_jd >= jd.size()) return false;
while(jd[now_jd] < frm_d[zq[now_zq]]){
now_jd++;
if(now_jd >= jd.size()) return false;
}
now_zq++;
now_jd++;
}
return true;
}
int main(){
n =read();
int u,v;
ll w;
fo(i,,n-){
u = read();
v = read();
w = read();
ins(u,v,w);
ins(v,u,w);
tot += w;
}
m = read();
fo(i,,m){
u = read();
tr[i] = u;
}
dfs(,);
ll lans = ,rans = tot,mid,ans = -;
while(lans <= rans){
mid = (lans+rans)>>;
if(check(mid)){
ans = mid;
rans = mid - ;
}else{
lans = mid + ;
}
}
cout<<ans;
return ;
}
//题解
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <set>
#include <map>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = ;
typedef long long LL;
multiset<int> S;
multiset<int>::iterator it;
int n,u,v,w,m,nownode;
LL f[maxn][];
int y[maxn];
int g[maxn][];
int sonTree[maxn];
int cnt[maxn];
int p[maxn];
int Min[maxn];
bool Leaf[maxn];
bool son[maxn];
struct Arm
{
int opt,time;
}A[maxn];
struct Graph
{
int node[maxn * ], len[maxn * ], next[maxn * ], v[maxn * ];
int en;
Graph(){
memset(v,,sizeof(v));
memset(next,, sizeof(next));
memset(len,,sizeof(len));
en = ;
}
void addEdge(int a,int b,int c)
{
en++; node[en] = b; len[en] = c; next[en] = v[a]; v[a] = en;
en++; node[en] = a; len[en] = c; next[en] = v[b]; v[b] = en;
}
}G;
void DFS(int x,int father)
{
sonTree[x] = nownode;
bool flag= true;
for (int j = G.v[x]; j; j = G.next[j])
{
if (G.node[j] != father)
{
//father[j] = x;
flag = false;
f[G.node[j]][] = G.len[j];
g[G.node[j]][] = x;
if (x==) nownode = G.node[j];
DFS(G.node[j],x);
}
}
Leaf[x] = flag;
}
void find_leaf(int x, int father)
{
if (cnt[x]>) return ;
if (Leaf[x])
{
son[nownode] = true;
return;
}
for (int j = G.v[x]; j ; j = G.next[j])
{
if (G.node[j] != father)
{
if (x==) nownode = G.node[j];
find_leaf(G.node[j], x);
}
}
}
bool ok(LL value)
{
S.clear();
int arm = ;
memset(cnt,,sizeof(cnt));
memset(son,,sizeof(son));
for (int i = ; i <= m ;++i)
{
int len = value;
int Pos = p[i];
for (int j = ; j>=; --j)
{
if (f[Pos][j]<=len && g[Pos][j]!=)
{
len-=f[Pos][j];
Pos =g[Pos][j];
}
}
if (Pos == )
{
A[arm].opt = p[i];
A[arm++].time = len;
} else
cnt[Pos]++;
}
find_leaf(,);
for (int i = ;i <= n;++i) Min[i]= -;
for (int i = ; i < arm ; ++ i)
{
if (son[sonTree[A[i].opt]])
{
if (Min[sonTree[A[i].opt]] ==- ||
A[Min[sonTree[A[i].opt]]].time > A[i].time)
Min[sonTree[A[i].opt]] = i;
}
}
int tot = ;
for (int i = ; i <= n;++i)
{
if (son[i] && Min[i] != - && A[Min[i]].time<f[i][])
{
A[Min[i]].time = -;
}else
if (son[i]) y[tot++] = f[i][];
}
sort(y,y+tot);
for (int i = ; i < arm;++i)
if (A[i].time != -)
S.insert(A[i].time); for (int i = tot-; i>=; --i)
{
if (S.lower_bound(y[i]) == S.end()) return false;
it = S.lower_bound(y[i]);
S.erase(it);
}
return true;
}
int main()
{
cin>>n;
for (int i = ;i < n;++ i)
{
scanf("%d %d %d",&u,&v,&w);
G.addEdge(u,v,w);
}
cin>>m ;
for (int i = ;i <= m;++i)
{
scanf("%d", &p[i]);
// cnt[p[i]] ++;
}
DFS(,);
/*for (int i = 1;i <= n; ++i)
{
cout <<i<<" "<<f[i][0]<<" "<<g[i][0] << endl;
}*/
for (int i = ; i <=; ++i)
for (int j = ; j <= n ;++j)
{
f[j][i] = f[j][i-]+ f[g[j][i-]][i-];
g[j][i] = g[g[j][i-]][i-];
} LL L = , R = (LL)n * round(10e9);
int ans = -;
while (L <= R)
{
LL mid = (L+R) /;
if (ok(mid)) R = mid-, ans = mid;
else L = mid+;
}
cout << ans << endl;
return ;
}
noip2012 疫情控制的更多相关文章
- Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)
Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增) Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...
- [NOIP2012]疫情控制 贪心 二分
题面:[NOIP2012]疫情控制 题解: 大体思路很好想,但是有个细节很难想QAQ 首先要求最大时间最小,这种一般都是二分,于是我们二分一个时间,得到一个log. 然后发现一个军队,越往上走肯定可以 ...
- NOIP2012 疫情控制 题解(LuoguP1084)
NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...
- NOIP2012疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
- [NOIP2012]疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
- [NOIp2012]疫情控制 题解
好久没更,强迫自己写一篇. 神 tm 大预言家出的题 注意到如果 \(x\) 小时可以控制住疫情,则 \(\forall x'>x\) 必然也可以控制住疫情,显然答案具有单调性,可以二分答案. ...
- NOIP2012疫情控制(二分答案+树上贪心)
H 国有n个城市,这 n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示 ...
- noip2012疫情控制 题解
题目大意 给出一棵n个节点的树,根是1,要在除根节点以外的点建立检查点,使得从每条根到叶子的路径上都至少存在一个检查点.检查点由军队来建立.初始军队的位置是给定的,移动军队走一条边需要花费这条边的权值 ...
- luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)
先二分出一个时间,把每个军队倍增往上跳到不能再跳 然后如果它能到1号点,就记下来它跳到1号点后剩余的时间:如果不能,就让它就地扎根,记一记它覆盖了哪些叶节点(我在这里用了dfs序+差分,其实直接dfs ...
随机推荐
- QTVA-2015-198545、WooYun-2015-104148 .NET Framework Arbitrary File Permissions Modify Vul
catalog . Description . Effected Scope . Exploit Analysis . Principle Of Vulnerability . Patch Fix 1 ...
- dedecms /member/flink_main.php SQL Injection Vul
catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述 会员模块中存在的SQL注入 Relevant Link http://w ...
- 服务器添加ipa MIME 类型,防止ipa下载后变zip后缀
客户反映apk文件下载 后缀会变为zip 打开mime.types文件 application/iphone pxl ipa application/vnd.android.package-a ...
- C#的参数修饰符out,params,ref
using System; namespace ParamsProgram { class TestParams { public static void Main(string[] args)//s ...
- 一起买beta版模块单元测试
一起买beta版模块接口单元测试 测试目的 保证代码质量,对各个模块进行单元测试,不仅可以有效地保证代码的可靠性,让模块在与别的模块整合时出现更少的错误. 而且不用每次启动程序而等待浪费时间. 单元描 ...
- wildfly jobss 同时连接多个数据源
由于需要从一个远程机器取数据.处理后保存到本地数据库处理.用 wildfly datasource 会报: [com.arjuna.ats.arjuna] (default task-6) ARJUN ...
- 捉襟见肘之UIView中contentMode属性
UIView.h @property(nonatomic) UIViewContentMode contentMode; // default is UIViewContentModeScaleToF ...
- POJ2187Beauty Contest(任意点的最远距离 + 凸包)
题目链接 题意:就是给N个点的坐标,然后求任意两个点距离的平方最大的值 枚举超时. 当明白了 最远距离的两个点一定在凸包上,一切就好办了.求出凸包,然后枚举 #include <iostream ...
- ES6之let(理解闭包)和const命令
ES6之let(理解闭包)和const命令 最近做项目的过程中,使用到了ES6,因为之前很少接触,所以使用起来还不够熟悉.因此购买了阮一峰老师的ES6标准入门,在此感谢阮一峰老师的著作. 我们知道,E ...
- 远程连接实验室的VPN
Windows 7 (win8类似)的用户请按以下步骤进行操作:1.点击“开始”菜单,然后点击“控制面板”,然后点击“查看网络和任务”.2.点击“设置新连接或网络”.3.点击“连接到工作区”,然后点击 ...