P1084 [NOIP2012 提高组] 疫情控制 - 树、贪心
题解
这篇题解是写给我自己看的,写得很简略,不保证读者能看懂。
大概算是自己做出来的?
首先发现答案有单调性,于是二分答案一下,问题转化成了问军队能否在 \(mid\) 时间内控制住疫情。
显然军队在非根的节点上时,往上走比往下走更优。于是通过对于每个有军队的点,找到深度最浅的祖先节点,满足祖先到军队的距离 \(\leq mid\)。
对于所有到不了根节点的军队,我们把它在树上标记一下,然后 dfs 一遍,看看根节点的哪些儿子被完全覆盖了。
有一个比较显然的贪心是,如果一个军队能到根节点,但到了根节点以后,剩下的时间不能让它回到它走过的那个根节点的儿子,并且这个儿子没有被覆盖,那么让这个军队驻扎在那个儿子一定是最优的。
对于剩下的军队,我们贪心地让它们跨过根节点与剩下的儿子进行匹配即可。
代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
template<typename T> void Read(T &x){
x=0;int _f=1;
char ch=getchar();
while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
x=x*_f;
}
template<typename T,typename... Args> void Read(T &x,Args& ...others){
Read(x);Read(others...);
}
typedef long long ll;
const int N=1e5+5;
int n,m,army[N];ll sumw;
vector<pair<int,ll>> G[N];
int fa[N],siz[N],hson[N];ll dep[N];
void HLD1(int u){
siz[u]=1;
for(auto i:G[u]){
int v=i.first;
if(v==fa[u]) continue;
fa[v]=u,dep[v]=dep[u]+i.second;
HLD1(v);siz[u]+=siz[v];
if(!hson[u]||siz[hson[u]]<siz[v]) hson[u]=v;
}
}
int top[N],num[N],rk[N],dfx;
void HLD2(int u,int tp){
top[u]=tp,num[u]=++dfx,rk[dfx]=u;
if(hson[u]) HLD2(hson[u],top[u]);
for(const auto& i:G[u]){
int v=i.first;
if(v==fa[u]||v==hson[u]) continue;
HLD2(v,v);
}
}
int bel[N];
void Color(int u,int col){
bel[u]=col;
for(const auto& i:G[u]){
if(i.first!=fa[u]) Color(i.first,col);
}
}
ll ps[N];
ll Anc(int u,ll k){
while(k>0&&u){
if(dep[u]-dep[fa[top[u]]]<=k){
k-=dep[u]-dep[fa[top[u]]];
u=fa[top[u]];
}else break;
}
if(!u) return 1;
int r=num[u],l=num[top[u]];
while(l<r){
int mid=(l+r)>>1;
if(ps[num[u]]-ps[mid]<=k) r=mid;
else l=mid+1;
}
return rk[l];
}
bool vis[N];
void Dfs(int u){
if(vis[u]) return;
bool fail=0;
for(const auto& i:G[u]){
int v=i.first;
if(v==fa[u]) continue;
vis[u]=1,Dfs(v);if(!vis[v]) fail=1;
}
vis[u]&=!fail;
}
bool Check(ll mid){
memset(vis,0,sizeof(bool)*(n+5));
static pair<ll,int> vec[N];
static ll st[N];
int len=0;
For(i,1,m){
int u=Anc(army[i],mid);
if(u!=1) vis[u]=1;
else vec[++len]={mid-dep[army[i]],bel[army[i]]};
}
Dfs(1);
if(vis[1]) return 1;
sort(vec+1,vec+len+1);
For(i,1,len){
if(!vis[vec[i].second]&&vec[i].first<=dep[vec[i].second]){
vis[vec[i].second]=1,vec[i].first=-1;
}
}
Dfs(1);
if(vis[1]) return 1;
st[0]=0;
for(const auto& i:G[1]) if(!vis[i.first]) st[++st[0]]=i.second;
sort(st+1,st+st[0]+1);
int j=1;
for(int i=1;i<=len&&j<=st[0];++i){
if(vec[i].first<st[j]) continue;
++j;
}
return j>st[0];
}
int main(){
Read(n);
int u,v,w;
For(i,1,n-1){
Read(u,v,w);sumw+=w;
G[u].push_back({v,w}),G[v].push_back({u,w});
}
Read(m);
For(i,1,m) Read(army[i]);
HLD1(1);HLD2(1,1);
For(i,2,n) ps[i]=ps[i-1]+dep[rk[i]]-dep[fa[rk[i]]];
for(auto i:G[1]) Color(i.first,i.first);
ll l=0,r=sumw;
while(l<r){
ll mid=(l+r)>>1;
if(Check(mid)) r=mid;
else l=mid+1;
}
printf("%lld\n",l);
return 0;
}
Written by Alan_Zhao