luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)
先二分出一个时间,把每个军队倍增往上跳到不能再跳
然后如果它能到1号点,就记下来它跳到1号点后剩余的时间;如果不能,就让它就地扎根,记一记它覆盖了哪些叶节点(我在这里用了dfs序+差分,其实直接dfs就行..)
然后对于那些叶节点没有被覆盖完全的(父亲为1号点的)子树,肯定需要一些已经到1号点的军队来走过去
如果它离1距离越远,肯定就希望用剩余时间越多的军队来走,除非是有一个剩余时间更少的军队本来就在这个子树里
看一看能不能符合要求的就行了
然而有很多要注意的地方:
0.一个军队只能用一次......(开始读错题 还在想为什么会有-1的情况)
1.只需要覆盖叶节点就行了,也就是说,统计这个子树有没有完全被覆盖的时候,不能统计到非叶节点
2.即使有军队本来在这个子树里,我也有可能不选这个军队来到这个子树里,因为它的剩余时间可能非常大
3.有可能到1号点的军队数不足覆盖掉那些没被覆盖的子树,这时候也是-1
4.每次judge要清零...
#include<bits/stdc++.h>
#define pa pair<int,int>
#define CLR(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=5e4+; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} struct Edge{
int b,ne;ll l;
}eg[maxn*];
int egh[maxn],ect;
int N,M,p[maxn];
int dfn[maxn][],tot,fa[maxn][];
int bel[maxn],cnt[maxn],tmp[maxn],tmp2[maxn];
int mim[maxn],id[maxn];
bool flag[maxn],islef[maxn];
ll dis[maxn][],rest[maxn]; inline void adeg(int a,int b,ll l){
eg[++ect].b=b;eg[ect].l=l;eg[ect].ne=egh[a];egh[a]=ect;
} void dfs(int x){
dfn[x][]=++tot;id[tot]=x;
for(int i=;fa[x][i]&&fa[fa[x][i]][i];i++){
fa[x][i+]=fa[fa[x][i]][i];
dis[x][i+]=dis[x][i]+dis[fa[x][i]][i];
}islef[x]=;
for(int i=egh[x];i;i=eg[i].ne){
int b=eg[i].b;
if(b==fa[x][]) continue;
fa[b][]=x;dis[b][]=eg[i].l;
if(x==) bel[b]=b;
else bel[b]=bel[x];
dfs(b);
islef[x]=;
}
dfn[x][]=tot;
} int getfe(int x,ll &lim){
for(int i=;i>=;i--){
if(fa[x][i]&&dis[x][i]<=lim) lim-=dis[x][i],x=fa[x][i];
}
return x;
} inline bool cmp(int a,int b){return rest[a]>rest[b];}
inline bool cmp2(int a,int b){return dis[a][]>dis[b][];} inline bool judge(ll m){
// printf("!!%lld:\n",m);
int n,i,j;
CLR(cnt,);
for(i=,j=;i<=M;i++){
rest[i]=m;
int x=getfe(p[i],rest[i]);
// printf("%d %d %lld\n",p[i],x,rest[i]);
if(x==) tmp[++j]=i;
else{
cnt[dfn[x][]]++;
cnt[dfn[x][]+]--;
}
}
n=j;sort(tmp+,tmp+n+,cmp);
CLR(flag,);
for(i=,j=;i<=N;i++){
j+=cnt[i];
if(j==&&islef[id[i]]) flag[bel[id[i]]]=;
}
CLR(mim,);
for(i=n;i;i--){
if((!flag[bel[p[tmp[i]]]])&&(!mim[bel[p[tmp[i]]]])){
mim[bel[p[tmp[i]]]]=i;
}
}
for(i=,j=;i<=N;i++){
if(fa[i][]!=||flag[i]) continue;
tmp2[++j]=i;
}m=j;
sort(tmp2+,tmp2+m+,cmp2);
if(n<m) return ;
for(i=,j=;i<=n&&j<=m;i++){
if(!tmp[i]) continue;
if(tmp[mim[tmp2[j]]]){
tmp[mim[tmp2[j]]]=;
i--;
}else{
if(rest[tmp[i]]<dis[tmp2[j]][]) return ;
tmp[i]=;
}j++;
}
return j>m;
} int main(){
// freopen("testdata (1).in","r",stdin);
int i,j,k;
N=rd();
for(i=;i<N;i++){
int a=rd(),b=rd(),c=rd();
adeg(a,b,c);adeg(b,a,c);
}dfs();
M=rd();
for(i=;i<=M;i++) p[i]=rd();
ll l=,r=1e15,ans=1e15+;
while(l<=r){
ll m=l+r>>;
if(judge(m)) ans=m,r=m-;
else l=m+;
}
if(ans==1e15+) printf("-1\n");
else printf("%lld\n",ans);
return ;
}
luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)的更多相关文章
- Luogu1084 NOIP2012D2T3 疫情控制 二分答案、搜索、贪心、倍增
题目传送门 题意太长就不给了 发现答案具有单调性(额外的时间不会对答案造成影响),故考虑二分答案. 贪心地想,在二分了一个时间之后,军队尽量往上走更好.所以我们预处理倍增数组,在二分时间之后通过倍增看 ...
- NOIP2012疫情控制(二分答案+树上贪心)
H 国有n个城市,这 n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示 ...
- Luogu P1084 疫情控制 | 二分答案 贪心
题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$ ...
- Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)
Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增) Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...
- [NOIP2012]疫情控制 贪心 二分
题面:[NOIP2012]疫情控制 题解: 大体思路很好想,但是有个细节很难想QAQ 首先要求最大时间最小,这种一般都是二分,于是我们二分一个时间,得到一个log. 然后发现一个军队,越往上走肯定可以 ...
- NOIP2012 疫情控制 题解(LuoguP1084)
NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...
- 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询
题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作 ...
- NOIP2012疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
- [NOIP2012]疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
随机推荐
- sql语句之随机查询记录和批量插入--基于mysql
本周遇到了好几次数据库方面的问题,一个是上一篇文章提到的因为要修改数据结构引起的在表间复制字段的需求,另一个就是这篇文章要写的:1,从某个数据表中按照某个字段不重复的随机选取几百条记录:2,然后把这些 ...
- 大数据入门第十二天——azkaban入门
一.概述 1.azkaban是什么 通过官方文档:https://azkaban.github.io/ Azkaban is a batch workflow job scheduler create ...
- # 《网络对抗》Exp1 PC平台逆向破解20155337祁家伟
<网络对抗>Exp1 PC平台逆向破解20155337祁家伟 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会 ...
- Git中使用amend解决提交冲突
问题描述 场景:当你提交的时候,发现跟要合并的流有冲突,你需要解决完冲突再次提交. 如果在SVN时代,你可以直接在本地解决完冲突再提交就可以了,因为SVN会把正确的代码先提交到服务器,至于 ...
- pygame 入门实例
本文基于win7(64) + py3.5(64)环境. 本文是这里的一篇学习笔记.加入了自己的理解. 本文最终目的是实现一个飞机躲避导弹的游戏. 1.核心概念 pygame 的核心概念有: Surfa ...
- 理解 NgModelController 中相关方法和属性
1. 理解$formatters和$parsers方法 angular的双向绑定可以实现view和model中的值自动同步,但有时候我们不想让用户输入的(view值)和发送给后台的(model值)并不 ...
- mac终端将本地代码push到github总结
1.创建一个github账号 2.在本地目录下创建一个本地仓库,用来存放代码 mkdir prepass_repository (/Users/gejuncheng/文件/prepass_reposi ...
- [CF1019C]Sergey's problem[构造]
题意 找出一个集合 \(Q\),使得其中的点两两之间没有连边,且集合中的点可以走不超过两步到达其他所有不在集合中的点.输出任意一组解. \(n\leq 10^6\) 分析 考虑构造,先从 \(1\) ...
- [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]
题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...
- node基础:文件系统-文件读取
node的文件读取主要分为同步读取.异步读取,常用API有fs.readFile.fs.readFileSync.还有诸如更底层的fs.read,以及数据流(stream),后面再总结下咯~ 直接上简 ...