• NOIP2012 疫情控制 题解(LuoguP1084)


    NOIP2012 疫情控制 题解(LuoguP1084)

    不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行。
    但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使向下走到深度为2的节点控制
    其他点,此时又可以进行另一个贪心,优先选择走到根节点还能再走的时间小的去控制深度一到二之间边权较小的。
    某大佬有更加详尽的讲解,参见这里

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    typedef long long ll;
    const int MAXN=50000+5;
    int anc[21][MAXN];
    ll tab[21][MAXN];
    struct Edge
    {
    	int t,v,n;
    }e[MAXN<<1];
    int cnt,n,m,scnt;
    int rsn[MAXN],siz[MAXN],army[MAXN],hd[MAXN],frm[MAXN];
    bool cvef[MAXN],cover[MAXN];
    typedef pair<int,int> pii;
    pii a[MAXN],c[MAXN];
    
    inline void build(int f,int t,int v)
    {
    	e[++cnt]=(Edge){t,v,hd[f]};
    	hd[f]=cnt;
    }
    
    void dfs1(int u)
    {
    	if(anc[0][u]==1)
    		frm[u]=u;
    	else frm[u]=frm[anc[0][u]];
    	for(int i=hd[u];i;i=e[i].n)
    	{
    		int v=e[i].t;
    		if(v==anc[0][u])
    			continue;
    		++siz[u];
    		anc[0][v]=u;
    		tab[0][v]=e[i].v;
    		for(int i=1;anc[i-1][v];++i)
    		{
    			anc[i][v]=anc[i-1][anc[i-1][v]];
    			tab[i][v]=tab[i-1][v]+tab[i-1][anc[i-1][v]];
    		}
    		dfs1(v);
    	}
    }
    
    void dfs2(int u)
    {
    	cvef[u]=1;
    	if(siz[u]>1)
    		return;
    	for(int i=hd[u];i;i=e[i].n)
    		if(e[i].t!=anc[0][u])
    			dfs2(e[i].t);
    }
    void initrt()
    {
    	for(int i=hd[1];i;i=e[i].n)
    	{
    		int v=e[i].t;
    		rsn[++scnt]=v;
    		dfs2(v);
    	}
    }
    
    bool check(ll mid)
    {
    	memset(cover,0,sizeof cover);
    	int cntc=0,cnta=0;
    	for(int i=1;i<=m;++i)
    	{
    		ll tmp=mid;
    		int pos=army[i];
    		for(int j=20;j>=0;--j)
    		{
    			if(anc[j][pos]&&tmp>=tab[j][pos])
    			{
    				tmp-=tab[j][pos];
    				pos=anc[j][pos];
    			}
    		}
    		if(pos!=1)
    		{
    			if(cvef[pos])
    				cover[frm[pos]]=1;
    		}
    		else
    			a[++cnta]=pii(tmp,frm[army[i]]);
    	}
    	for(int i=1;i<=scnt;++i)
    	{
    		if(!cover[rsn[i]])
    			c[++cntc]=pii(tab[0][rsn[i]],rsn[i]);
    	}
    	if(cntc>cnta)
    		return 0;
    	sort(a+1,a+cnta+1);
    	sort(c+1,c+cntc+1);
    	int j=1;
    	int t=cntc;
    	for(int i=1;i<=cnta;++i)
    	{
    		if(!cover[a[i].second])
    			cover[a[i].second]=1,--t;
    		else
    		{
    			while(j<=cntc&&cover[c[j].second])
    				++j;
    			if(a[i].first>=c[j].first)
    				cover[c[j].second]=1,++j,--t;
    		}
    	}
    	if(t>0)
    		return 0;
    	return 1;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	int x,y,z;
    	ll l=0,r=0;
    	for(int i=1;i<n;++i)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		build(x,y,z);
    		build(y,x,z);
    		r+=z;
    	}
    	scanf("%d",&m);
    	for(int i=1;i<=m;++i)
    		scanf("%d",&army[i]);
    	dfs1(1);
    	initrt();
    	if(m<scnt)
    	{
    		puts("-1");
    		return 0;
    	}
    	while(r-l>1)
    	{
    		ll mid=l+r>>1;
    		if(check(mid))
    			r=mid;
    		else
    			l=mid;
    	}
    	printf("%lld",r);
    	return 0;	
    }
    

    看来是只是贪心二分等基础算法我也不会QAQ

  • 相关阅读:
    关于服务器并发量的简单计算
    重温Android和Fragment生命周期
    JVM类加载机制
    设计六大原则总结
    Android Navigation使用
    Android BrocastReceiver解析
    Android LiveData使用
    Android Service解析
    Activity的生命周期和启动模式
    Java四种引用
  • 原文地址:https://www.cnblogs.com/chwhc/p/7725330.html
Copyright © 2020-2023  润新知