zoukankan      html  css  js  c++  java
  • 疫情控制sol

    疫情控制
    对于最值问题,在树上首先思考贪心和dp
    我们发现,一个军队要移动,一定是往上移动到深度最小的位置,或者是绕过root到一个root的子节点
    经过思考,正着做较难,但如果转为二分答案(因为答案有单调性),判定时我们有较好的贪心策略
    在实现的时候细节较多,要自己调一下
    将军队向上走的时候,用倍增,加上二分答案,复杂度两个log

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define SZ(x) ((int)x.size())
    #define ALL(x) x.begin(),x.end()
    #define U(i,u) for(register int i=head[u];i;i=nxt[i])
    #define rep(i,a,b) for(register int i=(a);i<=(b);++i)
    #define per(i,a,b) for(register int i=(a);i>=(b);--i)
    using namespace std;
    typedef long double ld;
    typedef long long ll;
    typedef unsigned int ui;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    template<class T> inline void read(T &x){
    	x=0;char c=getchar();int f=1;
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=f;
    }
    template<class T> inline void cmin(T &x, T y){x=x<y?x:y;}
    template<class T> inline void cmax(T &x, T y){x=x>y?x:y;}
    const int N=100010;
    const int LOG=21;
    int n,m,head[N],nxt[N<<1],v[N<<1],cnt,pos[N],anc[N][LOG],dep[N],len,tot,vis[N];
    int re[N],mix[N],pix[N];
    int whi[N];
    ll w[N<<1],dis[N][LOG],mx;
    struct node{
    	int b,id;ll c;
    }le[N],ne[N];
    void add(int x,int y,ll z){nxt[++cnt]=head[x];head[x]=cnt;v[cnt]=y;w[cnt]=z;}
    void dfs(int now,int fa,int de,ll fr,int wi){
    	if(fa==1)whi[now]=now;else whi[now]=wi;
    	dis[now][0]=fr;anc[now][0]=fa;dep[now]=de;U(i,now){
    		if(v[i]==fa)continue;
    		if(fa==1)dfs(v[i],now,de+1,w[i],now);
    		else dfs(v[i],now,de+1,w[i],wi);
    	}
    }
    void init(){
    	dfs(1,0,0,0,0);
    	rep(j,1,19)rep(i,1,n){
    		anc[i][j]=anc[anc[i][j-1]][j-1];
    		if(anc[i][j])dis[i][j]=dis[anc[i][j-1]][j-1]+dis[i][j-1];
    	}
    }
    void sup(int x,ll li,int id){
    	int tmp=whi[x];per(j,19,0){if(anc[x][j]>0)if(dis[x][j]<=li)li-=dis[x][j],x=anc[x][j];}
    	if(x==1){
    		le[++len].b=x,le[len].c=li,le[len].id=id;
    		if(li<mix[tmp])pix[tmp]=le[len].id,mix[tmp]=li;
    	}
    	else{vis[x]=1;}
    }
    void bl(int now,int fa){
    	bool flag=0,hs=0;
    	U(i,now){
    		if(fa==v[i])continue;hs=1;
    		bl(v[i],now);
    		if(vis[v[i]]==0)flag=1;
    	}
    	if(flag==0&&hs){
    		vis[now]=1;
    	}
    }
    bool cmp(node aa,node bb){
    	return aa.c<bb.c;
    }
    bool check(ll li){
    	memset(vis,0,sizeof(vis));
    	memset(mix,0x3f,sizeof(mix));
    	memset(re,0,sizeof(re));
    	tot=0;len=0;rep(i,1,m){sup(pos[i],li,i);}
    	bl(1,0);U(i,1){
    		if(!vis[v[i]]){
    			if(mix[v[i]]<0x3f3f3f3f&&mix[v[i]]<w[i])re[pix[v[i]]]=1;
    			else ne[++tot].b=v[i],ne[tot].c=w[i];
    		}
    	}
    	sort(le+1,le+len+1,cmp);
    	sort(ne+1,ne+tot+1,cmp);
    	int j=1;
    	rep(i,1,tot){
    		while(re[le[j].id])++j;
    		while(le[j].c<ne[i].c&&j<=len)++j;
    		if(j>len)return 0;
    		++j;
    	}
    	return 1;
    }
    int main(){
    	read(n);rep(i,1,n-1){int x,y;ll z;read(x);read(y);read(z);add(x,y,z);add(y,x,z);mx+=z;}
    	read(m);rep(i,1,m)read(pos[i]);init();
    	ll l=0,r=mx;
    	while(r-l>=3){
    		ll mid=(l+r)>>1;
    		if(check(mid))r=mid;
    		else l=mid+1;
    	}
    	for(ll i=l;i<=r;i++){if(check(i)){
    		printf("%lld
    ",i);
    		return 0;
    	}}
    	printf("-1
    ");
    	return 0;
    }
    /*
    8
    4 1 2
    3 4 8
    2 1 7
    7 8 8
    8 4 3
    6 1 7
    4 5 1
    7
    6 7 5 6 6 6 6
    
    ans=10;
    */
    
  • 相关阅读:
    Android Studio 开发
    Jsp编写的页面如何适应手机浏览器页面
    电影
    Oracle 拆分列为多行 Splitting string into multiple rows in Oracle
    sql server 2008 自动备份
    WINGIDE 激活失败
    python安装 错误 “User installations are disabled via policy on the machine”
    ble编程-外设发送数据到中心
    iOS开发-NSString去掉所有换行及空格
    ios9 字符串与UTF-8 互相转换
  • 原文地址:https://www.cnblogs.com/hangzz/p/13377605.html
Copyright © 2011-2022 走看看