luoguP4103 [HEOI2014]大工程

题意

建出虚树DP。
\(f[i]\)表示i的子树的第一问答案,\(minn[i]\)表示\(i\)的子树中到\(i\)最近的关键点,\(maxx[i]\)表示\(i\)的子树中到i距离最远的关键点,\(size[i]\)表示\(i\)子树中的关键点个数。

\(f[x]=\sum\limits_{y\in\ son_x}f[y]+size[y]*(tot-size[y])*w\)

\(minn\)\(maxx\)就类似树的直径。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000010;
const ll inf=1e18;
int n,m,cnt,t,top,tot,tim;
int head[maxn],size[maxn],a[maxn],dep[maxn],sta[maxn],dfn[maxn];
int f[maxn][25];
ll ans1,ans2;
ll g[maxn],maxx[maxn],minn[maxn];
bool check[maxn];
struct edge{int to,nxt,dis;}e[maxn<<1];
inline int read()
{
	char c=getchar();int res=0,f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
	return res*f;
}
inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
inline void add(int u,int v,int w)
{
	e[++cnt].nxt=head[u];
	head[u]=cnt;
	e[cnt].to=v;
	e[cnt].dis=w;
}
void dfs_pre(int x,int fa)
{
	dep[x]=dep[fa]+1;dfn[x]=++tim;
	for(int i=1;i<=t;i++)f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==fa)continue;
		f[y][0]=x;dfs_pre(y,x);
	}
}
inline int lca(int x,int y)
{
	if(dep[x]>dep[y])swap(x,y);
	for(int i=t;~i;i--)if(dep[f[y][i]]>=dep[x])y=f[y][i];
	if(x==y)return x;
	for(int i=t;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	return f[x][0];
}
inline int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
void dfs(int x)
{
	//cerr<<"test::"<<x<<endl;
	g[x]=0;
	maxx[x]=-inf,minn[x]=inf;size[x]=0;
	if(check[x])size[x]=1,minn[x]=0,maxx[x]=0;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		dfs(y);size[x]+=size[y];
		g[x]+=g[y]+1ll*e[i].dis*size[y]*(tot-size[y]);
		ans1=min(ans1,minn[x]+minn[y]+e[i].dis);
		minn[x]=min(minn[x],minn[y]+e[i].dis);
		ans2=max(ans2,maxx[x]+maxx[y]+e[i].dis);
		maxx[x]=max(maxx[x],maxx[y]+e[i].dis);
	}
}
void solve()
{
	cnt=0;ans1=inf;ans2=-inf;
	tot=read();
	for(int i=1;i<=tot;i++)a[i]=read(),check[a[i]]=1;
	sort(a+1,a+tot+1,cmp);
	sta[top=1]=1,head[1]=0;
	for(int i=1;i<=tot;i++)
	{
		if(a[i]==1)continue;
		int x=lca(a[i],sta[top]);
		if(x!=sta[top])
		{
			while(top>1&&dfn[sta[top-1]]>dfn[x])add(sta[top-1],sta[top],dis(sta[top-1],sta[top])),top--;
			if(x!=sta[top-1])head[x]=0,add(x,sta[top],dis(x,sta[top])),sta[top]=x;
			else add(x,sta[top],dis(x,sta[top])),top--;
		}
		head[a[i]]=0;sta[++top]=a[i];
	}
	for(int i=1;i<top;i++)add(sta[i],sta[i+1],dis(sta[i],sta[i+1]));
	dfs(1);
	printf("%lld %lld %lld\n",g[1],ans1,ans2);
	for(int i=1;i<=tot;i++)check[a[i]]=0;
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	n=read();t=(int)log2(n)+1;
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		add(u,v,1),add(v,u,1);
	}
	dfs_pre(1,0);
	m=read();
	for(int i=1;i<=m;i++)solve();
	return 0;
} 
posted @ 2019-12-03 15:45  nofind  阅读(86)  评论(0编辑  收藏  举报