LUOGU P1084 疫情控制(二分+贪心+树上倍增)
解题思路
比较神的一道题。首先发现是最小值问题,并且具有单调性,所以要考虑二分答案。其次有一个性质是军队越靠上越优,所以我们要将所有的军队尽量向上提,这一过程我们用倍增实现。发现这时有两种军队,一种是到根之后可以继续移动,另一种不行。那么记录下来那些到根之后可以移动的点和可以继续移动的距离,存到一个结构体里,顺便还要记录下来每个根节点的子节点中剩余路程最短的点。继续一遍\(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 疫情控制(二分+贪心+树上倍增)的更多相关文章
- Luogu P1084 疫情控制 | 二分答案 贪心
题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$ ...
- luogu P1084疫情控制 二分
链接 loj luogu太水不要去了. 思路 二分. 每个军队在一定的时间内越往上越好. 注意一个军队可以跨过1去帮别的. 把能到1脚下的点都存下来特判. 有一种情况是这个子树内只有一个军队,但这个军 ...
- 洛谷P1084 疫情控制 [noip2012] 贪心+树论+二分答案 (还有个小bugQAQ
正解:贪心+倍增+二分答案 解题报告: 正好想做noip的题目然后又想落实学长之前讲的题?于是就找上了这题 其实之前做过,70,然后实在细节太多太复杂就不了了之,现在再看一遍感觉又一脸懵了... 从标 ...
- 洛谷P1084 疫情控制(贪心+倍增)
这个题以前写过一遍,现在再来写,感觉以前感觉特别不好写的细节现在好些多了,还是有进步吧. 这个题的核心思想就是贪心+二分.因为要求最小时间,直接来求问题将会变得十分麻烦,但是如果转换为二分答案来判断可 ...
- NOIP2012疫情控制(二分答案+树上贪心)
H 国有n个城市,这 n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示 ...
- 洛谷 P1084 疫情控制 —— 二分+码力
题目:https://www.luogu.org/problemnew/show/P1084 5个月前曾经写过一次,某个上学日的深夜,精疲力竭后只有区区10分,从此没管... #include< ...
- luogu P1084 疫情控制
传送门 首先,所有军队又要尽量往上走,这样才能尽可能的封锁更多的到叶子的路径 而随着时间的增加,能封锁的路径也就越来越多,所以可以二分最终的时间 然后对于每个时间,就让能走到根的军队走到根,记录到根上 ...
- 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)
洛谷题目传送门 费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比... 话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是\(O(n\log n\log nw)\)的 ...
- 洛谷P1084 疫情控制
题目 细节比较多的二分+跟LCA倍增差不多的思想 首先有这样一个贪心思路,深度越低的检查点越好,而最长时间和深度具有单调性,即给定时间越长,每个军队能向更浅的地方放置检查点.因此可以考虑二分时间,然后 ...
随机推荐
- angularJs input框绑定ng-model后js获取不到问题
搬运自:https://blog.csdn.net/fenglongmiao/article/details/81545993 与其他指令一样,ng-controller指令也会创建一个子级作用域,因 ...
- vue keep-alive缓存问题
搬运自:https://blog.csdn.net/dongguan_123/article/details/80910231 我的问题:列表页 > 详情页a > 支付页 > ...
- cocos2dx 3.9 微信授权登陆后游戏进程结束解决办法
找到 Cocos2dxActivity.java 文件夹 里面的 onDestroy() 方法 if (mGLSurfaceView != null) { Cocos2dxHel ...
- Go学习笔记:初识Go语言
Go语言简介 Go语言是Google(谷歌)公司开发的一款静态型.编译型并自带垃圾回收机制和并发的编程语言. Go语言的风格类似于C语言.其语法在C语言的基础上进行了大幅的简化,去掉了不需要的表达式括 ...
- DOM 对象和jQuery对象的转换
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- [原创] Java 流布局管理器 FlowLayout
参数原型: public FlowLayout(int align, int hgap, int vgap) { this.hgap = hgap; this.vgap = vgap; setAlig ...
- JavaWeb学习篇之----Tomcat中配置数字证书以及网络传输数据中的密码学知识
今天是学习JavaWeb的第二天,我们来了解什么呢?就了解一下Tomcat中配置数字证书的相关内容,但是在说这部分内容的时候,我们貌似得先说一下数字证书的相关概念,那说到数字证书的时候我们还得了解一些 ...
- Python 列表,元组,字典
0)字符串切片 py_str = 'python' >>>py_str[0] #取第一个字符串,返回值为"p",超出范围会报错 >>>py_st ...
- LeetCode 176. Second Highest Salary (第二高的薪水)
题目标签: 题目给了我们一个工资表,让我们返回第二高的工资. 利用Max,把第一高的工资找到,然后利用 NOT IN,去找到第二高的工资. Java Solution: Runtime: 153ms ...
- spring-boot-configuration-processor
spring默认使用yml中的配置,但有时候要用传统的xml或properties配置,就需要使用spring-boot-configuration-processor了 引入pom依赖 <de ...