Luogu P4103 [HEOI2014]大工程
虚树+DP
建出虚树;第一问考虑每条边的贡献是 \(w(u,v)\times sz_v\times (k-sz_v)\) ;第二问第三问每次有新子树时,先计算答案,再更新最小值和最大值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=1000010;
const ll Inf=1e15;
int n,m,k;
int vr[N<<1],nxt[N<<1],fir[N],w[N<<1],cnt;
int sz[N],d[N],dfn[N],pre[N],top[N],son[N],h[N],num;
ll ans1,ans2,mx[N],mn[N],ans;
int stk[N]; bool vis[N];
inline void add(int u,int v,int ww)
{vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,w[cnt]=ww;}
inline void dfs(int u) {
sz[u]=1,dfn[u]=++num;
for(R i=fir[u];i;i=nxt[i]) {
R v=vr[i];
if(d[v]) continue;
pre[v]=u,d[v]=d[u]+1;
dfs(v);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
}
inline void dfs2(int u,int tp) {
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(R i=fir[u];i;i=nxt[i]) {
R v=vr[i];
if(!top[v]) dfs2(v,v);
}
}
inline int lca(int u,int v) {
while(top[u]!=top[v]) {
if(d[top[u]]<d[top[v]]) swap(u,v);
u=pre[top[u]];
} return d[u]<d[v]?u:v;
}
inline int dis(int u,int v)
{return d[u]+d[v]-2*d[lca(u,v)];}
inline bool cmp(const int& a,const int& b)
{return dfn[a]<dfn[b];}
inline void dp(int u) {
if(vis[u]) sz[u]=1,mx[u]=mn[u]=0;
else mx[u]=-Inf,mn[u]=Inf,sz[u]=0;
for(R i=fir[u];i;i=nxt[i]) {
R v=vr[i];
dp(v);
sz[u]+=sz[v];
ans+=1ll*w[i]*sz[v]*(k-sz[v]);
ans1=min(ans1,mn[u]+mn[v]+w[i]);
mn[u]=min(mn[u],mn[v]+w[i]);
ans2=max(ans2,mx[u]+mx[v]+w[i]);
mx[u]=max(mx[u],mx[v]+w[i]);
}
}
inline void main() {
n=g();
for(R i=1,u,v;i<n;++i)
u=g(),v=g(),add(u,v,0),add(v,u,0);
d[1]=1,dfs(1),dfs2(1,1);
memset(fir,0,sizeof fir);
m=g();
while(m--) {
k=g();
for(R i=1;i<=k;++i) h[i]=g(),vis[h[i]]=1;
sort(h+1,h+k+1,cmp);
R top;
fir[1]=cnt=0;
stk[top=1]=1;
for(R i=1+(h[1]==1),l;i<=k;++i) {
l=lca(stk[top],h[i]);
if(l!=stk[top]) {
while(dfn[l]<dfn[stk[top-1]])
add(stk[top-1],stk[top],dis(stk[top-1],stk[top])),--top;
if(dfn[l]>dfn[stk[top-1]])
fir[l]=0,add(l,stk[top],dis(l,stk[top])),stk[top]=l;
else add(l,stk[top],dis(l,stk[top])),--top;
}
fir[h[i]]=0,stk[++top]=h[i];
}
for(R i=1;i<top;++i) add(stk[i],stk[i+1],dis(stk[i],stk[i+1]));
ans=0,ans1=Inf,ans2=-Inf,dp(1);
printf("%lld %lld %lld\n",ans,ans1,ans2);
for(R i=1;i<=k;++i) vis[h[i]]=false;
}
}
} signed main() {Luitaryi::main(); return 0;}
2020.01.17