1. 程式人生 > >BZOJ 2286 [Sdoi2011]消耗戰

BZOJ 2286 [Sdoi2011]消耗戰

name inline ret type spa const clock namespace for

題解:對詢問點建立虛樹

然後在虛樹上Dp

每個點父邊邊權為這個點到根的邊權最小值

一開始學了假的虛樹

一開始竟然沒想到父邊邊權可以這樣賦

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=500009;
const int inf=2000000000;
typedef long long Lint;

int n,m,T;

int cntedge;
int head[maxn];
int to[maxn],nex[maxn],dist[maxn];
void Addedge(int x,int y,int z){
//	cout<<x<<‘ ‘<<y<<‘ ‘<<z<<endl;
	nex[++cntedge]=head[x];
	to[cntedge]=y;
	dist[cntedge]=z;
	head[x]=cntedge;
}

int dfsclock;
int father[maxn],depth[maxn],minedge[maxn];
int L[maxn],R[maxn];
void Dfs(int now,int fa,int ecost){
	L[now]=++dfsclock;
	father[now]=fa;
	depth[now]=depth[fa]+1;
	minedge[now]=min(minedge[fa],ecost);
	
	for(int i=head[now];i;i=nex[i]){
		if(to[i]==fa)continue;
		Dfs(to[i],now,dist[i]);
	}
	R[now]=++dfsclock;
}

int f[maxn][20];
void LCAinit(){
	for(int i=1;i<=n;++i)f[i][0]=father[i];
	for(int j=1;j<=19;++j){
		for(int i=1;i<=n;++i){
			f[i][j]=f[f[i][j-1]][j-1];
		}
	}
}
int Getlca(int u,int v){
	if(depth[u]<depth[v])swap(u,v);
	for(int j=19;j>=0;--j){
		if(depth[f[u][j]]>=depth[v])u=f[u][j];
	}
	if(u==v)return u;
	for(int j=19;j>=0;--j){
		if(f[u][j]!=f[v][j]){
			u=f[u][j];v=f[v][j];
		}
	}
	return f[u][0];
}

int h[maxn];
int ene[maxn];
int cmp(const int &rhs1,const int &rhs2){
	return L[rhs1]<L[rhs2];
}

int S[maxn],top;
inline int intree(int x,int y){
	return (L[x]>=L[y])&&(R[x]<=R[y]);
}


Lint g[maxn];
int q[maxn];
void Dp(int x,int fa){
	if(ene[x]){
		q[x]=1;g[x]=inf;return;
	}
	q[x]=g[x]=0;
	for(int i=head[x];i;i=nex[i]){
		if(to[i]==fa)continue;
		Dp(to[i],x);
		q[x]|=q[to[i]];
		if(q[to[i]])g[x]+=min(g[to[i]],dist[i]*1LL);
	}
}

int Xsize;
int a[maxn];

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n-1;++i){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		Addedge(x,y,z);
		Addedge(y,x,z);
	}
	
	minedge[0]=inf;
	Dfs(1,0,inf);
	LCAinit();
	
	memset(head,0,sizeof(head));
	scanf("%d",&T);
	while(T--){
//		cout<<"begin"<<endl;
		scanf("%d",&n);
		for(int i=1;i<=n;++i){
			scanf("%d",&h[i]);ene[h[i]]=1;
		}
		sort(h+1,h+1+n,cmp);
//		for(int i=1;i<=n;++i)cout<<h[i]<<‘ ‘;
//		cout<<endl;
		cntedge=Xsize=0;
		S[top=1]=1;a[++Xsize]=1;
		for(int i=1;i<=n;++i){
			int lca=Getlca(h[i],S[top]);
			while(!intree(h[i],S[top])){
				if(intree(lca,S[top-1])){
					Addedge(lca,S[top],minedge[S[top]]);--top;break;
				}
				Addedge(S[top-1],S[top],minedge[S[top]]);--top;
			}
			if(S[top]!=lca){
				S[++top]=lca;a[++Xsize]=lca;
			}
			S[++top]=h[i];a[++Xsize]=h[i];
		}
		while(top>1){
			Addedge(S[top-1],S[top],minedge[S[top]]);--top;
		}
		Dp(1,0);
		printf("%lld\n",g[1]);
		for(int i=1;i<=Xsize;++i){
			ene[a[i]]=head[a[i]]=0;
		}
	}
	return 0;
}

  

BZOJ 2286 [Sdoi2011]消耗戰