[HEOI2014]大工程

Description
国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。
我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。
在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。
现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间新建C(k,2)条新通道。
现在对于每个计划,我们想知道:
1.这些新通道的代价和
2.这些新通道中代价最小的是多少
3.这些新通道中代价最大的是多少

Input
第一行 n 表示点数。
接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。
点从 1 开始标号。 接下来一行 q 表示计划数。
对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。
第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。

Output
输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。

Sample Input
10
2 1
3 2
4 1
5 2
6 4
7
8 6
9 7
10 9
5
2
5 4
2
10 4
2
5 2
2
6 1
2
6 1

Sample Output
3 3 3
6 6 6
1 1 1
2 2 2
2 2 2

HINT
n<=1000000
q<=50000并且保证所有k之和<=2*n


先吐槽一句:这个样例真良心

标记点个数与\(n\)同阶?上虚树!建出虚树后考虑求解答案,权值和二次换根即可,最大最小值在dfs的时候记录最大次大,最小次小,然后更新即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
	int x=0,f=1; char ch=gc();
	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
	return x*f;
}
inline int read(){
	int x=0,f=1; char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x<0)	putchar('-'),x=-x;
	if (x>9)	print(x/10);
	putchar(x%10+'0');
}
const int N=1e6;
int ID[N+10];
bool cmp(int x,int y){return ID[x]<ID[y];}
struct S1{
	int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,Time;
	int size[N+10],top[N+10],fa[N+10],deep[N+10],Rem[N+10];
	void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
	void insert(int x,int y){join(x,y),join(y,x);}
	void build(int x){
		deep[x]=deep[fa[x]]+1,size[x]=1;
		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
			if (son==fa[x])	continue;
			fa[son]=x,build(son);
			size[x]+=size[son];
			if (size[Rem[x]]<size[son])	Rem[x]=son;
		}
	}
	void dfs(int x){
		if (!x)	return;
		ID[x]=++Time;
		top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
		dfs(Rem[x]);
		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
			if (son==Rem[x]||son==fa[x])	continue;
			dfs(son);
		}
	}
	int LCA(int x,int y){
		while (top[x]!=top[y]){
			if (deep[top[x]]<deep[top[y]])	swap(x,y);
			x=fa[top[x]];
		}
		return deep[x]<deep[y]?x:y;
	}
	int dis(int x,int y){return abs(deep[x]-deep[y]);}
}HLD;//Heavy Light Decomposition
struct S2{
	struct node{
		int Mx,Sx;
		int Mn,Sn;
		node(){Mx=Sx=-inf,Mn=Sn=inf;}
		void clear(){Mx=Sx=-inf,Mn=Sn=inf;}
		void init(){Mx=Mn=0;}
	}f[N+10];
	int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],val[(N<<1)+10];
	bool mark[N+10];
	int size[N+10],A[N+10],stack[N+10];
	int tot,Max,Min,All; ll Ans;
	void updata(node &x,node y,int v){
		node z=y; z.Mx+=v,z.Mn+=v;
		if (x.Mx<z.Mx)	x.Sx=x.Mx,x.Mx=z.Mx;
		else	if (x.Sx<z.Mx)	x.Sx=z.Mx;
		
		if (x.Mn>z.Mn)	x.Sn=x.Mn,x.Mn=z.Mn;
		else	if (x.Sn>z.Mn)	x.Sn=z.Mn;
	}
	void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
	void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
	void insert(int x,int y){insert(x,y,HLD.dis(x,y));}
	void rebuild(int m){
		int top=0; tot=0;
		sort(A+1,A+1+m,cmp);
		stack[++top]=1;
		for (int i=1;i<=m;i++){
			int x=A[i],lca=HLD.LCA(stack[top],x);
			if (x==1)	continue;
			if (lca==stack[top]){
				stack[++top]=x;
				continue;
			}
			while (true){
				int y=stack[top-1];
				if (ID[y]>=ID[lca]){
					insert(stack[top--],y);
					continue;
				}else{
					if (lca==stack[top])	break;
					insert(stack[top],lca);
					stack[top]=lca; break;
				}
			}
			stack[++top]=x;
		}
		while (top>1){
			insert(stack[top],stack[top-1]);
			top--;
		}
	}
	void dfs(int x,int fa){
		f[x].clear(); size[x]=mark[x];
		if (mark[x])	f[x].init();
		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
			if (son==fa)	continue;
			dfs(son,x),size[x]+=size[son];
			updata(f[x],f[son],val[p]);
		}
		Max=max(Max,f[x].Mx+f[x].Sx);
		Min=min(Min,f[x].Mn+f[x].Sn);
	}
	void sum(int x,int fa){
		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
			if (son==fa)	continue;
			sum(son,x);
			Ans+=1ll*size[son]*(All-size[son])*val[p];
		}
		now[x]=0;
	}
	void work(){
		int m=read();
		for (int i=1;i<=m;i++)	mark[A[i]=read()]=1;
		rebuild(m),Max=-inf,Min=inf;
		dfs(1,0),All=size[1],Ans=0,sum(1,0);
		printf("%lld %d %d\n",Ans,Min,Max);
		for (int i=1;i<=m;i++)	mark[A[i]]=0;
	}
}T;
int main(){
	int n=read();
	for (int i=1;i<n;i++){
		int x=read(),y=read();
		HLD.insert(x,y);
	}
	HLD.build(1),HLD.dfs(1);
	int m=read();
	for (int i=1;i<=m;i++)	T.work();
	return 0;
}
posted @ 2019-01-10 11:44  Wolfycz  阅读(158)  评论(0编辑  收藏  举报