1. 程式人生 > 實用技巧 >疫情控制sol

疫情控制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\n",i);
		return 0;
	}}
	printf("-1\n");
	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;
*/