• 疫情控制


    题目描述

    HHH 国有 nn n个城市,这 nnn 个城市用n−1 n-1 n1条双向道路相互连通构成一棵树,11 1号城市是首都,也是树中的根节点。

    HH H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。

    现在,在 HHH 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。

    请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。

    输入输出格式

    输入格式:

    第一行一个整数n nn,表示城市个数。

    接下来的 n−1n-1n1 行,每行3 3 3个整数,u,v,wu,v,wu,v,w,每两个整数之间用一个空格隔开,表示从城市 uu u到城市v vv 有一条长为 www 的道路。数据保证输入的是一棵树,且根节点编号为 111。

    接下来一行一个整数 mmm,表示军队个数。

    接下来一行 mm m个整数,每两个整数之间用一个空格隔开,分别表示这 mmm 个军队所驻扎的城市的编号。

    输出格式:

    一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出−1-11。

    输入输出样例

    输入样例#1: 复制
    4 
    1 2 1 
    1 3 2 
    3 4 3 
    2 
    2 2
    输出样例#1: 复制
    3

    说明

    【输入输出样例说明】

    第一支军队在 222 号点设立检查点,第二支军队从 222 号点移动到3 33 号点设立检查点,所需时间为 333 个小时。

    【数据范围】

    保证军队不会驻扎在首都。

    对于 20%的数据,2≤n≤102≤ n≤ 102n10;

    对于 40%的数据,2≤n≤50,0<w<1052 ≤n≤50,0<w <10^52n50,0<w<105;

    对于 60%的数据,2≤n≤1000,0<w<1062 ≤ n≤1000,0<w <10^62n1000,0<w<106;

    对于 80%的数据,2≤n≤10,0002 ≤ n≤10,0002n10,000;

    对于 100%的数据,2≤m≤n≤50,000,0<w<1092≤m≤n≤50,000,0<w <10^92mn50,000,0<w<109。

    NOIP 2012 提高组 第二天 第三题

    很有意思的一题;

    用到了倍增,二分,树上操作

    因为答案具有单调性所以选择二分答案;

    判断过程中将所有士兵往上跳(长度小于等于二分值)

    判断该士兵能否到1节点,若能则将其压入数组,并存入剩余步数(用于贪心

    不能则标记能到的最高点;

    之后依次判断每个节点控制的子树底端是否已被覆盖,没有的话就将root点压入一个数组,并存入到1点的距离

    之后就模拟看能否将每个点覆盖

    (loj数据有点强过不了。。只过了洛谷的。。)

    #include<bits/stdc++.h>
    #define ll long long 
    using namespace std;
    
    const int maxn = 3e5+10;
    
    ll n,head[maxn],size,r[maxn],f[maxn][20],maxd,deep[maxn],m,val[maxn],root[maxn],tt,ct;
    
    ll dis[maxn][30];
    
    struct edge{
    	ll v,w,nex;
    }e[maxn<<1];
    
    struct node{
    	ll id,w;
    }kzqc[maxn],wbkz[maxn];
    
    bool cmp(node a,node b){
    	return a.w<b.w;
    }
    
    void adde(ll u,ll v,ll w){
    	e[size].v=v;e[size].w=w;e[size].nex=head[u];head[u]=size++;
    }
    
    bool vis[maxn],vis2[maxn];
    
    void dfs(){
    	queue<int>q;
    	q.push(1);
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		if(f[u][0]!=-1) maxd=max(maxd,deep[u]=deep[f[u][0]]+1);
    		for(int i=head[u];~i;i=e[i].nex){
    			int v=e[i].v;
    			if(v==f[u][0]) continue;
    			if(u==1) root[v]=v;
    			else root[v]=root[u];
    			dis[v][0]=e[i].w;f[v][0]=u;
    			q.push(v);
    		}
    	}
    }
    
    void doubling(){
    	for(ll j=1;j<=maxd;j++)
    	    for(ll i=1;i<=n;i++){
    	    	if(f[i][j-1]!=-1) f[i][j]=f[f[i][j-1]][j-1],dis[i][j]=dis[i][j-1]+dis[f[i][j-1]][j-1];
    		}
    }
    
    bool _dfs(ll u){
    	if(r[u]==1&&!vis[u]) return 1;
    	for(ll i=head[u];~i;i=e[i].nex){
    		if(e[i].v==f[u][0]) continue;
    		if(vis[u]) vis[e[i].v]=vis[u];
    		if(_dfs(e[i].v)) return 1;
    	}
    	return 0;
    }
    
    bool check(ll mid){
    	memset(kzqc,0,sizeof(kzqc));memset(wbkz,0,sizeof(wbkz));memset(vis,0,sizeof(vis));memset(vis2,0,sizeof(vis2));
    	tt=0,ct=0;
    	for(ll i=1;i<=m;i++){
    		ll lu=mid;ll u=val[i];
    		for(ll j=maxd;j>=0;j--){
    			if(f[u][j]!=-1&&dis[u][j]<=lu) lu-=dis[u][j],u=f[u][j];
    		}
    		if(u==1) {
    			kzqc[++tt].id=root[val[i]],kzqc[tt].w=lu;
    		}
    		else vis[u]=1;
    	}
    	for(ll i=head[1];~i;i=e[i].nex){
    		ll v=e[i].v;
    		if(!vis[v]&&_dfs(v)){
    			wbkz[++ct].id=root[v],wbkz[ct].w=e[i].w;vis2[root[v]]=1;
    		}
    	}
    	sort(kzqc+1,kzqc+1+tt,cmp);sort(wbkz+1,wbkz+1+ct,cmp);
    	ll t=1;
    	for(ll i=1;i<=tt;i++){
    		if(vis2[kzqc[i].id]) vis2[kzqc[i].id]=0;
    		else if(kzqc[i].w>=wbkz[t].w) vis2[wbkz[t].id]=0;
    		while(!vis2[wbkz[t].id]) {
    			t++;if(t>ct) return 1;
    		}
    	}
    	return t>ct;
    }
    
    int main(){
    	freopen("in.txt","r",stdin);
    	scanf("%lld",&n);
    	memset(f,-1,sizeof(f));memset(head,-1,sizeof(head));
    	ll lef=0,righ=12484069034;
    	for(ll i=1;i<n;i++){
    		ll u,v,w;scanf("%lld%lld%lld",&u,&v,&w);
    		adde(u,v,w);adde(v,u,w);r[u]++,r[v]++;;
    	}
    	dfs();
    	maxd=(ll)(log(maxd)/log(2));
    	doubling();
    	scanf("%lld",&m);
    	ll ans=-1;
    	for(int i=1;i<=m;i++) scanf("%lld",val+i);
    	while(lef<=righ){
    		ll mid=(lef+righ)>>1;
    		if(check(mid)) {ans=mid;righ=mid-1;}
    		else lef=mid+1;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    SQL Server存储过程(二)
    WPF 小知识 (设置背景图)
    关于SQL Server中索引使用及维护简介
    学习asp.net比较完整的流程(转)
    web开发常用默认端口
    接口和类的几大区别
    WEB建站规划之建站目的
    个人经验:页面无刷新传输数据的多种方法总结
    旅游电子商务探讨
    vs2008中文版提供下载(包含中文msdn)
  • 原文地址:https://www.cnblogs.com/plysc/p/10538037.html
Copyright © 2020-2023  润新知