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
  • 相关阅读:
    【CSS学习】--- 背景
    线程运行诊断
    Mysql变量、存储过程、函数、流程控制
    设计模式之外观模式(门面模式)
    Spring的JdbcTemplate使用教程
    @AspectJ注解的value属性
    自定义Yaml解析器替换Properties文件
    @Import导入自定义选择器
    Spring中Bean命名源码分析
    Java操作fastDFS
  • 原文地址:https://www.cnblogs.com/alan-zhao-2007/p/p1084-sol.html
Copyright © 2011-2022 走看看