题目在这里
正解是虚树,然而我并不会写。。。。
所以我写了点分治。
对于一棵子树,暴力找出重心,然后计算跨越重心的部分对答案的贡献。
具体方法如下:对于重心的每一棵子树,算出每个询问中在这棵子树中的每个节点到重心距离的最大值,最小值,距离和以及个数,然后dfs的时候更新一下。
(速度巨慢,bzoj上倒数)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <deque>
#include <queue>
#include <map>
#include <set>
#include <ctime>
using namespace std;
typedef long long LL;
const int MAXN=1000005,MAXQ=50005,INF=(1<<29);
int n,m,tot,fst[MAXN],pre[MAXN*2],to[MAXN*2],dis[MAXN],son[MAXN],size[MAXN],maxsize[MAXN];
struct Node
{
int _max,_min,cnt; LL sum;
void init() { _max=-INF,_min=INF,sum=0,cnt=0; }
void update(int x) { _max=max(_max,dis[x]),_min=min(_min,dis[x]),sum+=LL(dis[x]),cnt++; }
}res[MAXQ],ans[MAXQ];
void modify(int x,int q)
{
ans[q]._min=min(ans[q]._min,dis[x]+res[q]._min);
ans[q]._max=max(ans[q]._max,dis[x]+res[q]._max);
ans[q].sum+=LL(res[q].cnt)*LL(dis[x])+res[q].sum;
}
vector<int> Ask[MAXN]; bool vis[MAXN];
int Get()
{
char ch; int v=0; bool f=false;
while (!isdigit(ch=getchar())) if (ch=='-') f=true; v=ch-48;
while (isdigit(ch=getchar())) v=v*10+ch-48;
if (f) return -v;else return v;
}
void add(int x,int y)
{
pre[++tot]=fst[x],fst[x]=tot,to[tot]=y;
pre[++tot]=fst[y],fst[y]=tot,to[tot]=x;
}
void dfs_root(int x,int fa)
{
son[++tot]=x; size[x]=1,maxsize[x]=0;
for (int i=fst[x];i;i=pre[i])
{
int y=to[i];
if (!vis[y] && fa!=y) dfs_root(y,x),size[x]+=size[y],maxsize[x]=max(size[y],maxsize[x]);
}
}
void dfs_init(int x,int fa)
{
son[++tot]=x;
for (int i=0;i<Ask[x].size();i++) modify(x,Ask[x][i]);
for (int i=fst[x];i;i=pre[i])
{
int y=to[i];
if (!vis[y] && y!=fa) dis[y]=dis[x]+1,dfs_init(y,x);
}
}
void work(int x)
{
tot=0,dis[x]=0;
for (int i=fst[x];i;i=pre[i])
{
int y=to[i],st=tot; dis[y]=1;
if (!vis[y])
{
dfs_init(y,x);
for (int j=st+1;j<=tot;j++)
for (int k=0;k<Ask[son[j]].size();k++) res[Ask[son[j]][k]].update(son[j]);
}
}
for (int i=0;i<Ask[x].size();i++) modify(x,Ask[x][i]);
for (int i=1;i<=tot;i++)
{
dis[son[i]]=0;
for (int j=0;j<Ask[son[i]].size();j++) res[Ask[son[i]][j]].init();
}
}
void dfs(int x)
{
tot=0; int root;
dfs_root(x,-1); int ms=MAXN;
for (int i=1;i<=tot;i++)
{
int tmp=max(maxsize[son[i]],tot-size[son[i]]);
if (tmp<ms) ms=tmp,root=son[i];
}
work(root); vis[root]=true;
for (int i=fst[root];i;i=pre[i])
{
int y=to[i];
if (!vis[y]) dfs(y);
}
}
void Put(int x)
{
char ch[21]; int tot=0; if (x==0) { putchar('0'); return; }
while (x) ch[++tot]=x%10,x/=10;
for (;tot;tot--) putchar(ch[tot]+48);
}
void Putll(LL x)
{
char ch[21]; int tot=0; if (x==0) { putchar('0'); return; }
while (x) ch[++tot]=x%LL(10),x/=LL(10);
for (;tot;tot--) putchar(ch[tot]+48);
}
int main()
{
//freopen("project.in","r",stdin);
//freopen("project.out","w",stdout);
n=Get(); int u,v;
for (int i=1;i<=n-1;i++) u=Get(),v=Get(),add(u,v);
m=Get();
for (int i=1;i<=m;i++)
{
tot=Get(); for (int j=1;j<=tot;j++) u=Get(),Ask[u].push_back(i);
res[i].init(),ans[i].init();
}
dfs(1);
for (int i=1;i<=m;i++) Putll(ans[i].sum),putchar(32),Put(ans[i]._min),
putchar(32),Put(ans[i]._max),puts("");
return 0;
}