3611: [Heoi2014]大工程

继续水虚树。

这题60S的时限把我吓坏了。

然而3000多MS就A了,有幸到了rank 4,nice!。

一开始还在纠结是点分治还是DP,后来想想既然能DP何不DP呢。

于是就DP了。

显然要维护三个量。

ans2和ans3都好说,参照树上直径的求法就好了,次长+最长+1变形一下。

ans1的话比较麻烦,手画个图看看,目测是当前子树的边与其他子树的边对应,然后其他子树的边再和当前子树的算一下,动手推一推就好了。

然后就OK了。

果然像Clj所说,一开始还很有意思,做多了就审美疲劳了(才一两个好不好)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int read(){
	int x=0;char ch;
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x;
}
const int N=1000000+5;
const int inf=1e9;
struct Edge{int to,next,v;}e[N<<1];
int head[N],cnt;
int siz[N],son[N],dep[N],fa[N],top[N];
int dfn[N],dfs_clock;
void ins(int u,int v){
	if(u==v)return;
	e[++cnt]=(Edge){v,head[u],dep[v]-dep[u]};head[u]=cnt;
}
void dfs1(int u){
	siz[u]=1;son[u]=0;dfn[u]=++dfs_clock;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;if(v==fa[u])continue;
		dep[v]=dep[u]+1;fa[v]=u;
		dfs1(v);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}
}
void dfs2(int u,int tp){
	top[u]=tp;
	if(son[u])dfs2(son[u],tp);
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v!=son[u]&&v!=fa[u])dfs2(v,v);
	}
}
int lca(int u,int v){
	while(top[u]!=top[v]){
		if(dep[top[u]]>=dep[top[v]])u=fa[top[u]];
		else v=fa[top[v]];
	}
	return dep[u]<dep[v]?u:v;
}
ll sum[N],ans1;
int mx[N],mi[N],ans2,ans3; 
bool build[N]; 
void dp(int u){
	siz[u]=build[u];
	mx[u]=build[u]?0:-inf;
	mi[u]=build[u]?0:inf;
	sum[u]=0;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		dp(v);
		ans1+=(sum[u]+siz[u]*e[i].v)*siz[v]+sum[v]*siz[u];
		siz[u]+=siz[v];
		sum[u]+=sum[v]+siz[v]*e[i].v;
		ans2=min(ans2,mi[u]+mi[v]+e[i].v);
		ans3=max(ans3,mx[u]+mx[v]+e[i].v);
		mi[u]=min(mi[u],mi[v]+e[i].v);
		mx[u]=max(mx[u],mx[v]+e[i].v);
	}
	head[u]=0;
}
int h[N];
int st[N],tp;
bool cmp(int i,int j){
	return dfn[i]<dfn[j];
}
void solve(){
	int k=read();
	for(int i=1;i<=k;i++){
		h[i]=read();
		build[h[i]]=true;
	}
	sort(h+1,h+1+k,cmp);
	tp=cnt=0;
	st[++tp]=1;
	for(int i=1;i<=k;i++){
		int now=h[i],f=lca(now,st[tp]);
		if(f==st[tp]){st[++tp]=now;continue;}
		while(f==lca(now,st[tp-1])){
			ins(st[tp-1],st[tp]);
			tp--;f=lca(now,st[tp]);
		}
		ins(f,st[tp]);
		st[tp]=f;st[++tp]=now;
	}
	while(--tp)ins(st[tp],st[tp+1]);
	ans1=0;ans2=inf;ans3=-inf;
	dp(1);
	printf("%lld %d %d\n",ans1,ans2,ans3);
	for(int i=1;i<=k;i++)build[h[i]]=false;
}
int main(){
	int n=read();
	int u,v;
	for(int i=1;i<n;i++){
		u=read();v=read();
		ins(u,v);ins(v,u);
	}
	dfs1(1);dfs2(1,1);
	memset(head,0,sizeof(head));
	int q=read();
	while(q--)solve();
	return 0;
}
	


你可能感兴趣的:(3611: [Heoi2014]大工程)