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 5
8 6
9 7
10 9
5
2
5 4
2
10 4
2
5 2
2
6 1
2
6 1
2 1
3 2
4 1
5 2
6 4
7 5
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
6 6 6
1 1 1
2 2 2
2 2 2
HINT
n<=1000000
q<=50000并且保证所有k之和<=2*n
正解:虚树+树形dp。
对于每次询问,建立一棵虚树。在虚树上跑树形dp。这题有点麻烦,主要是dp的姿势吧。。求总数就是记录当前点size,然后加加减减就行了,求最小值就看当前点是否是关键点,如果是关键点就直接取它的子树路径最小值,否则就是它的两个儿子的子树路径最小值相加。求最大值同理。
//It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define N (1000010)
#define il inline
#define RG register
#define ll long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
struct edge{ int nt,to,dis; }g[2*N];
int head[N],size[N],top[N],fa[N],son[N],dis[N],dep[N],dfn[N],ed[N],a[N],st[N],vi[N],sz[N],dp1[N],dp2[N],n,m,k,u,v,q,num,cnt,ans1,ans2;
ll dp[N];
il int gi(){
RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
}
il void insert(RG int from,RG int to){ g[++num]=(edge){head[from],to},head[from]=num; return; }
il int cmp(const int &a,const int &b){ return dfn[a]<dfn[b]; }
il void dfs(RG int x){
dp[x]=0,dp1[x]=inf,dp2[x]=0,sz[x]=vi[x];
for (RG int i=head[x];i;i=g[i].nt){
RG int v=g[i].to,d=dis[v]-dis[x]; dfs(v);
sz[x]+=sz[v]; dp[x]+=dp[v]+(ll)sz[v]*(ll)(k-sz[v])*(ll)d;
ans1=min(ans1,dp1[x]+dp1[v]+d),dp1[x]=min(dp1[x],dp1[v]+d);
ans2=max(ans2,dp2[x]+dp2[v]+d),dp2[x]=max(dp2[x],dp2[v]+d);
}
if (vi[x]) ans1=min(ans1,dp1[x]),ans2=max(ans2,dp2[x]),dp1[x]=0;
head[x]=0; return;
}
il void dfs1(RG int x,RG int p){
dfn[x]=++cnt,dep[x]=dep[p]+1,fa[x]=p,size[x]=1;
for (RG int i=head[x];i;i=g[i].nt){
RG int v=g[i].to; if (v==p) continue;
dis[v]=dis[x]+1; dfs1(g[i].to,x); size[x]+=size[v];
if (size[son[x]]<=size[v]) son[x]=v;
}
ed[x]=cnt; return;
}
il void dfs2(RG int x,RG int p,RG int a){
top[x]=a; if (son[x]) dfs2(son[x],x,a);
for (RG int i=head[x];i;i=g[i].nt){
RG int v=g[i].to;
if (v==p || v==son[x]) continue;
dfs2(v,x,v);
}
head[x]=0; return;
}
il int lca(RG int u,RG int v){
while (top[u]!=top[v]){
if (dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v] ? u : v;
}
il void work(){
n=gi(); for (RG int i=1;i<n;++i) u=gi(),v=gi(),insert(u,v),insert(v,u); dfs1(1,0),dfs2(1,0,1); q=gi();
for (RG int i=1;i<=q;++i){
k=gi(),m=k; for (RG int i=1;i<=k;++i) vi[a[i]=gi()]=1; sort(a+1,a+k+1,cmp); RG int Lca=a[1];
for (RG int i=2;i<=k;++i){ if (ed[a[i-1]]<dfn[a[i]]) a[++m]=lca(a[i-1],a[i]); Lca=lca(Lca,a[i]); }
a[++m]=Lca; sort(a+1,a+m+1,cmp); m=unique(a+1,a+m+1)-a-1; RG int top=1; st[top]=a[1],num=0;
for (RG int i=2;i<=m;++i){ while (top && ed[st[top]]<dfn[a[i]]) top--; insert(st[top],a[i]),st[++top]=a[i]; }
ans1=inf,ans2=0,dfs(Lca); printf("%lld %d %d\n",dp[Lca],ans1,ans2); for (RG int i=1;i<=m;++i) vi[a[i]]=0;
}
return;
}
int main(){
File("project");
work();
return 0;
}