zoukankan      html  css  js  c++  java
  • 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
    ",l);
    	return 0;
    }
    
    Written by Alan_Zhao
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 校门外的树
    Java实现 蓝桥杯VIP 算法训练 统计单词个数
    Java实现 蓝桥杯VIP 算法训练 统计单词个数
    Java实现 蓝桥杯VIP 算法训练 开心的金明
    Java实现 蓝桥杯VIP 算法训练 开心的金明
    Java实现 蓝桥杯 算法训练 纪念品分组
    Java实现 蓝桥杯 算法训练 纪念品分组
    Java实现 蓝桥杯VIP 算法训练 校门外的树
    Java实现 蓝桥杯VIP 算法训练 统计单词个数
    Java实现 蓝桥杯VIP 算法训练 开心的金明
  • 原文地址:https://www.cnblogs.com/alan-zhao-2007/p/p1084-sol.html
Copyright © 2011-2022 走看看