传送门

解题思路

  比较神的一道题。首先发现是最小值问题,并且具有单调性,所以要考虑二分答案。其次有一个性质是军队越靠上越优,所以我们要将所有的军队尽量向上提,这一过程我们用倍增实现。发现这时有两种军队,一种是到根之后可以继续移动,另一种不行。那么记录下来那些到根之后可以移动的点和可以继续移动的距离,存到一个结构体里,顺便还要记录下来每个根节点的子节点中剩余路程最短的点。继续一遍\(dfs\),可以求出那些需要被占领的根节点的子节点,然后记录他们到根的距离。把两个数组从大到小排序,贪心的选取剩余路程大于需要占领的子节点到根的距离的那些点去占领,注意也要考虑到不移动的情况。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib> using namespace std;
const int MAXN = 50005;
typedef long long LL; inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
} int n,m,head[MAXN],cnt,to[MAXN<<1],nxt[MAXN<<1],val[MAXN<<1],a[MAXN];
int f[MAXN][23],ar[MAXN],resid[MAXN],cntb,cnta;
LL dis[MAXN][23],ans,sum,resmin[MAXN];
bool vis[MAXN],use[MAXN]; struct Data{
int id;LL res;
friend bool operator<(const Data A,const Data B){
return A.res>B.res;
}
}tmp[MAXN],b[MAXN]; inline void add(int bg,int ed,int w){
to[++cnt]=ed,nxt[cnt]=head[bg],val[cnt]=w,head[bg]=cnt;
} void dfs(int x,int fa,int w){
f[x][0]=fa;dis[x][0]=w;int u;
for(int i=1;i<=20;i++){
f[x][i]=f[f[x][i-1]][i-1];
dis[x][i]=dis[x][i-1]+dis[f[x][i-1]][i-1];
// printf("f[%d][%d]=%d\n",x,i,f[x][i]);
}
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==fa) continue;
dfs(u,x,val[i]);
}
} bool dfs2(int x,int fa){
int u;bool flag=false,ok=true;if(vis[x]) return 1;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==fa) continue;flag=1;
if(!dfs2(u,x)){ok=false;
if(x==1) b[++cntb].id=u,b[cntb].res=val[i];
else return false;
}
}
if(!flag) return false;
return ok;
} inline bool check(LL lim){
cnta=0,cntb=0;int L=1;
memset(use,0,sizeof(use));
memset(vis,0,sizeof(vis));
memset(resmin,0,sizeof(resmin));
memset(resid,0,sizeof(resid));
for(int i=1;i<=m;i++){
ar[i]=a[i];LL now=lim;
for(int j=20;j>=0;j--)
if(f[ar[i]][j]>1 && now>=dis[ar[i]][j]) now-=dis[ar[i]][j],ar[i]=f[ar[i]][j];
if(f[ar[i]][0]==1 && now-dis[ar[i]][0]>0) {
tmp[++cnta].res=now-dis[ar[i]][0];tmp[cnta].id=i;
if(tmp[cnta].res<resmin[ar[i]] || !resmin[ar[i]])
resmin[ar[i]]=tmp[cnta].res,resid[ar[i]]=i;
}
else vis[ar[i]]=1;
}
dfs2(1,0);if(!cntb) return true;
sort(tmp+1,tmp+1+cnta);sort(b+1,b+1+cntb);use[0]=1;
for(int i=1;i<=cntb;i++){
if(!use[resid[b[i].id]]) {use[resid[b[i].id]]=1;continue;}
while(L<=cnta && (tmp[L].res<b[i].res || use[tmp[L].id])) L++;
if(L>cnta) return false;use[tmp[L].id]=1;L++;
}
return true;
} int main(){
// freopen("1.in","r",stdin);
n=rd();int x,y,z;
for(int i=1;i<n;i++){
x=rd(),y=rd(),z=rd();
add(x,y,z),add(y,x,z);sum+=z;
}
m=rd();for(int i=1;i<=m;i++) a[i]=rd();
dfs(1,0,0);LL l=0,r=sum,mid;
while(l<=r) {
mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld\n",ans);
return 0;
}
/*
10
2 1 3
2 3 4
1 4 7
5 1 9
6 1 2
4 7 9
7 8 8
9 8 8
1 10 2
5
2 8 5 4 2
*/

LUOGU P1084 疫情控制(二分+贪心+树上倍增)的更多相关文章

  1. Luogu P1084 疫情控制 | 二分答案 贪心

    题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$ ...

  2. luogu P1084疫情控制 二分

    链接 loj luogu太水不要去了. 思路 二分. 每个军队在一定的时间内越往上越好. 注意一个军队可以跨过1去帮别的. 把能到1脚下的点都存下来特判. 有一种情况是这个子树内只有一个军队,但这个军 ...

  3. 洛谷P1084 疫情控制 [noip2012] 贪心+树论+二分答案 (还有个小bugQAQ

    正解:贪心+倍增+二分答案 解题报告: 正好想做noip的题目然后又想落实学长之前讲的题?于是就找上了这题 其实之前做过,70,然后实在细节太多太复杂就不了了之,现在再看一遍感觉又一脸懵了... 从标 ...

  4. 洛谷P1084 疫情控制(贪心+倍增)

    这个题以前写过一遍,现在再来写,感觉以前感觉特别不好写的细节现在好些多了,还是有进步吧. 这个题的核心思想就是贪心+二分.因为要求最小时间,直接来求问题将会变得十分麻烦,但是如果转换为二分答案来判断可 ...

  5. NOIP2012疫情控制(二分答案+树上贪心)

    H 国有n个城市,这 n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示 ...

  6. 洛谷 P1084 疫情控制 —— 二分+码力

    题目:https://www.luogu.org/problemnew/show/P1084 5个月前曾经写过一次,某个上学日的深夜,精疲力竭后只有区区10分,从此没管... #include< ...

  7. luogu P1084 疫情控制

    传送门 首先,所有军队又要尽量往上走,这样才能尽可能的封锁更多的到叶子的路径 而随着时间的增加,能封锁的路径也就越来越多,所以可以二分最终的时间 然后对于每个时间,就让能走到根的军队走到根,记录到根上 ...

  8. 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)

    洛谷题目传送门 费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比... 话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是\(O(n\log n\log nw)\)的 ...

  9. 洛谷P1084 疫情控制

    题目 细节比较多的二分+跟LCA倍增差不多的思想 首先有这样一个贪心思路,深度越低的检查点越好,而最长时间和深度具有单调性,即给定时间越长,每个军队能向更浅的地方放置检查点.因此可以考虑二分时间,然后 ...

随机推荐

  1. 2019-3-15-在-Windows-Defender-设置文件夹白名单提升-VisualStudio-编译速度

    title author date CreateTime categories 在 Windows Defender 设置文件夹白名单提升 VisualStudio 编译速度 lindexi 2019 ...

  2. 读书笔记---《Docker 技术入门与实践》---其一

    一.镜像1.1.搜索 搜索所有nginx镜像 $ docker search nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Officia ...

  3. HTTP状态码(转)

    转自菜鸟教程:https://www.runoob.com/http/http-status-codes.html HTTP状态码共分为5种类型: HTTP状态码分类 分类 分类描述 1** 信息,服 ...

  4. Jenkins 搭建 .NET FrameWork 持续集成环境

    本文不赘述如何安装 Jenkins,如有需要请看之前文章,这里我们主要搭建 .Net 环境.本文是在 Windows 环境下安装的 Jenkins 进行操作     一.安装所需环境     这里我们 ...

  5. Java KMP算法代码

    1. KMP 算法(字符串匹配算法)较 BF(朴素的字符串匹配)算法有哪些改进 1) 在主串和子串匹配的过程中,主串不再回退,只改变子串的比较位置. 2) 为子串生成对应的next数组,每次匹配失败, ...

  6. 在 input 的 placeholder中 使用iconfont

    写在前面 产品要求放大镜和文字放在一起.用定位,位置不准确,就会导致手机上错位,丑的一批. 进入正题 如何在input的 placeholder 中使用图标呢? 以阿里巴巴的矢量图标库为例, 现在有三 ...

  7. centos7 开机自动执行shell脚本

    centos7 开机自动执行shell脚本 90十80 关注 2018.12.23 09:37 字数 309 阅读 485评论 0喜欢 0 自己新建一个脚本,如centnet-service.sh 经 ...

  8. redis笔记--------Jedis使用

    redis安装和启动就不说了 一.准备工作 1.redis -cli -p 6379 2.eclipse中新建项目,并导入jedis相关包 3.测试jedis连通性 二.Jedis常用API (哈希) ...

  9. DXP 常用功能

    1. PCB布板篇 t+s: 从原理图对应到pcb图中 F11: 修改顶层,底层信息 v+f: 回到PCB板中 i+l: 放置到画的矩形框内 对齐功能: ctrl + shift + t: 顶部对齐 ...

  10. ActiveMQ 反序列化漏洞(CVE-2015-5254)

    java -jar jmet-0.1.0-all.jar -Q event -I ActiveMQ -s -Y "touch /tmp/success" -Yp ROME 192. ...