传送门

首先,所有军队又要尽量往上走,这样才能尽可能的封锁更多的到叶子的路径

而随着时间的增加,能封锁的路径也就越来越多,所以可以二分最终的时间

然后对于每个时间,就让能走到根的军队走到根,记录到根上一个节点和剩余时间,然后按时间排序;不能走到的就在能走到的最上面的点打标记.然后遍历树一遍,把所有的儿子被打标记的点打标记;然后把根的没打标记的儿子提出来,和之前到达根的军队一一匹配:把那些儿子按照到根的距离从大到小排序,对于每个儿子,考虑用退回上一个节点匹配,不行就用剩余时间足够的匹配,都不行就用当前军队退回去匹配,然后考虑下一个军队

有点毒瘤似不似

注:保存到根的节点建议用\(multiset\),向下面代码里面写的能过洛谷上的题,但是仍有问题懒得改了

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define inf 2099999999
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define db double
#define eps (1e-5) using namespace std;
const int N=50000+10;
il LL rd()
{
re LL x=0,w=1;re char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
LL w[N<<1];
il void add(int x,int y,LL z)
{
++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;
++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=z,hd[y]=tot;
}
struct nnn
{
LL x;int la;
bool operator < (const nnn &a) const{return x>a.x;}
}st[N<<1];
int n,m,nn,a[N],fa[N][17],tt,tp,cn[N];
LL s[N][17],di[N],l,r,ans,so[N];
bool v[N];
il bool cmp(int a,int b){return di[a]>di[b];}
void dfs(int x)
{
r=max(r,di[x]);
for(int j=1;j<=nn;j++) fa[x][j]=fa[fa[x][j-1]][j-1],s[x][j]=(fa[x][j]>0)?(s[x][j-1]+s[fa[x][j-1]][j-1]):(1ll<<50);
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==fa[x][0]) continue;
fa[y][0]=x,s[y][0]=w[i],di[y]=di[x]+w[i];
dfs(y);
}
}
void dd(int x)
{
if(v[x]) return;
v[x]=true;
int cnt=0;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==fa[x][0]) continue;
dd(y);
v[x]&=v[y];
++cnt;
}
if(!cnt) v[x]=false;
}
il bool check(LL ti)
{
memset(v,0,sizeof(v));
memset(cn,0,sizeof(cn));
tt=tp=0;
for(int i=1;i<=m;i++)
{
if(di[a[i]]<ti)
{
int nw=a[i];
for(int j=nn;j>=0;j--) if(fa[nw][j]>1) nw=fa[nw][j];
st[++tt]=(nnn){ti-di[a[i]],nw},++cn[nw];
continue;
}
int nw=a[i];LL ss=0;
for(int j=nn;j>=0;j--) if(ss+s[nw][j]<=ti&&fa[nw][j]>1) ss+=s[nw][j],nw=fa[nw][j];
if(nw>1) v[nw]=true;
}
sort(st+1,st+tt+1);
dd(1);
for(int i=hd[1];i;i=nt[i])
if(!v[to[i]]) so[++tp]=to[i];
sort(so+1,so+tp+1,cmp);
int j=1;
for(int i=1;i<=tt&&j<=tp;i++)
{
if(cn[so[j]]>0) --cn[so[j]],--i,v[so[j]]=true;
else if(st[i].x>=di[so[j]]&&cn[st[i].la]>0) --cn[st[i].la],v[so[j]]=true;
else if(cn[st[i].la]>0) --cn[st[i].la],st[++tt]=(nnn){st[i].x,st[i].la},v[st[i].la]=true;
while(j<=tp&&v[so[j]]==true) ++j;
}
return j>tp;
} int main()
{
n=rd(),nn=log(n)/log(2)+1;
for(int i=1;i<n;i++)
{
int x=rd(),y=rd(),z=rd();
add(x,y,z);
}
dfs(1);
m=rd();
for(int i=1;i<=m;i++) a[i]=rd();
l=0,r<<=1ll,ans=1ll<<60;
while(l<=r)
{
LL mid=(l+r)>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
printf("%lld\n",ans<(1ll<<60)?ans:-1);
return 0;
}

luogu P1084 疫情控制的更多相关文章

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

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

  2. luogu P1084疫情控制 二分

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

  3. LUOGU P1084 疫情控制(二分+贪心+树上倍增)

    传送门 解题思路 比较神的一道题.首先发现是最小值问题,并且具有单调性,所以要考虑二分答案.其次有一个性质是军队越靠上越优,所以我们要将所有的军队尽量向上提,这一过程我们用倍增实现.发现这时有两种军队 ...

  4. [NOIP2012] 提高组 洛谷P1084 疫情控制

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

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

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

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

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

  7. NOIP2012 洛谷P1084 疫情控制

    Description: H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情 ...

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

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

  9. 2018.09.26洛谷P1084 疫情控制(二分+倍增)

    传送门 好题啊. 题目要求的最大值最小,看到这里自然想到要二分答案. 关键在于怎么检验. 显然对于每个点向根走比向叶节点更优. 因此我们二分答案之后,用倍增将每个点都向上跳到跳不动为止. 这时我们ch ...

随机推荐

  1. jquery遍歷

    遍歷是什麼? jquery的遍歷指的是移動,就是從選中的元素根據元素之間的關係移動,直到找到目標元素.從DOM樹中,可以進行向上移動(祖先),向下移動(子孫)和水平移動(同胞). 祖先就是父,祖父,曾 ...

  2. html web服务器

    web服务器可以发布网站,从而使得网站可以被全世界访问: 在自己服务器上托管自己的网站的要求: 硬件搭建:强大的服务器硬件,保证24小时高速连接, 软件搭建:服务器授权比客户端授权更贵: 人工费:环境 ...

  3. 学习笔记之csrf

    CBV 添加 csrf 第一种: 指定方法方面添加 装饰器 @memethod_decorator(xxx) 第二种 全部添加: 注意 在类名前: @method_decorator(xxx,name ...

  4. hdu 3949 XOR (线性基)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=3949 题意: 给出n个数,从中任意取几个数字异或,求第k小的异或和 思路: 线性基求第k小异或和,因为题 ...

  5. Codeforces Round #436 (Div. 2) A,B,D

    A. Fair Game 题目链接:http://codeforces.com/contest/864/problem/A 水题 #include<iostream> #include&l ...

  6. MT【208】埃尔米特恒等式

    设$S=\sum\limits_{k=1}^{+\infty}[\dfrac{116+3^{k-1}}{3^k}]\\T=\sum\limits_{k=1}^{+\infty}[\dfrac{116+ ...

  7. 搜索Ex

    哎呀好几天没写POI题解了 (>﹏<) 看着摇曳不定的小旗子深深惶恐 打算开始肝洛谷试炼场的提高分区了[对我就是这么菜… 搜索Ex 比暴搜不错得多的题 洛谷P1514 引水入城 拆成两问来 ...

  8. 自学Linux Shell12.3-case命令

    点击返回 自学Linux命令行与Shell脚本之路 12.3-case命令 有了case命令,就不需要写出所有elif语句来不停的检查同一个变量的值了.case命令会采用列表格式来检查单个变量的多个值 ...

  9. 【BZOJ3821/UOJ46】玄学(二进制分组,线段树)

    [BZOJ3821/UOJ46]玄学(二进制分组,线段树) 题面 BZOJ UOJ 题解 呜,很好的题目啊QwQ. 离线做法大概可以线段树分治,或者直接点记录左右两次操作时的结果,两个除一下就可以直接 ...

  10. harmakik

    Solution 对于原树一个节点\(x\): \(f_x(h)\)表示,\(x\)作为一个深度为\(h\)的点时,\(x\)及其子树的安排方案有多少(不考虑\(x\)具体在深度为\(h\)的哪个点) ...