P1084 [NOIP2012 提高组] 疫情控制(倍增&贪心&二分)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1084 [NOIP2012 提高组] 疫情控制(倍增&贪心&二分)相关的知识,希望对你有一定的参考价值。
P1084 [NOIP2012 提高组] 疫情控制(倍增&贪心&二分)
1.倍增预处理出 f [ i ] [ j ] , d [ i ] [ j ] f[i][j],d[i][j] f[i][j],d[i][j] 即结点 i i i到自己第 2 j 2^j 2j个父亲是谁、距离是多少。
2.二分答案
3.每次二分时,每个结点尽靠近根结点,即向上提,这样是最优的,能控制更多叶子。
4.把不能到达的树根的儿子结点的所有位置标记为驻扎,因此这个点不能再往上走了。
5.把能到达树根的儿子结点的位置和多余时间记录。
6.dfs搜一下哪些树根的儿子结点还需要驻扎。
7.对可移动的军队排序,然后不能再回到根节点直接驻扎,因为剩余时间更多的也可以移动那个点,而该节点位置走了之后,需要更多的时间占用。
8.把剩余时间和需要占据的时间进行双指针操作。
9.若能满足所有需要占据的点,则返回真,否则返回假。
code
// Problem: P1084 [NOIP2012 提高组] 疫情控制
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1084
// Memory Limit: 125 MB
// Time Limit: 2000 ms
// Date: 2021-07-14 14:47:24
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=5e4+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
int n,m,b[N];
struct edge{
int to,nt,w;
}e[N<<1];
int h[N],cnt;
void add(int u,int v,int w){
e[++cnt]={v,h[u],w},h[u]=cnt;
e[++cnt]={u,h[v],w},h[v]=cnt;
}
int d[N][20],f[N][20];
void dfs(int u,int fa){
f[u][0]=fa;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to,w=e[i].w;
if(f[u][0]==v) continue;
d[v][0]=w;
dfs(v,u);
}
}
bool st[N];
bool dfs(int u){
bool ok=1;
if(st[u]) return 1;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to;
if(f[u][0]==v) continue;
ok=0;
if(!dfs(v)) return 0;
}
if(ok) return 0;
return 1;
}
PII aa[N];
int bb[N],cc[N];
bool nd[N];
int sta;
bool cmp(PII &a,PII &b){
return a.se<b.se;
}
bool ck(ll tot){
mst(st,0);
mst(aa,0),mst(bb,0);
mst(cc,0);
mst(nd,0);
int ca=0,cb=0,ct=0;
for(int i=1;i<=m;i++){
ll tmp=0;int x=b[i];
for(int j=sta;~j;j--) if(f[x][j]>1&&tmp+d[x][j]<=tot){
tmp+=d[x][j];
x=f[x][j];
}
if(f[x][0]==1&&tmp+d[x][0]<=tot){
aa[++ca]=make_pair(x,tot-tmp-d[x][0]);
}
else st[x]=1;
}
for(int i=h[1];i;i=e[i].nt)
if(!dfs(e[i].to)) nd[e[i].to]=1;
sort(aa+1,aa+ca+1,cmp);
for(int i=1;i<=ca;i++)
if(nd[aa[i].fi]&&aa[i].se<d[aa[i].fi][0])
nd[aa[i].fi]=0;
else bb[++cb]=aa[i].se;
for(int i=h[1];i;i=e[i].nt)
if(nd[e[i].to]) cc[++ct]=d[e[i].to][0];
int i=1,j=1;
sort(bb+1,bb+cb+1),sort(cc+1,cc+ct+1);
while(i<=cb&&j<=ct){
if(bb[i]>=cc[j]) i++,j++;
else i++;
}
return j>ct;
}
int main(){
scanf("%d",&n);
ll l=0,r=0;
for(int i=1,u,v,w;i<n;i++){
scanf("%d%d%d",&u,&v,&w);add(u,v,w);r+=w;
}
sta=log2(n)+1;
dfs(1,0);
for(int j=1;j<=sta;j++)
for(int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
d[i][j]=d[i][j-1]+d[f[i][j-1]][j-1];
}
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
ll ans=-1;
while(l<=r){
int mid=l+r>>1;
if(ck(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld\\n",ans);
return 0;
}
以上是关于P1084 [NOIP2012 提高组] 疫情控制(倍增&贪心&二分)的主要内容,如果未能解决你的问题,请参考以下文章
洛谷P1084 [NOIP2012提高组Day2T3]疫情控制