传送门:bzoj3611
C(k,2)条边就是把所有点之间都连起来…然后询问所有两两之间边的最大值和最小值。(读错题意了蜜汁尴尬)
注意询问节点总数不超过2n,当然是建虚树,然后在虚树上dp啦。
建虚树的方法是这样的,要维护一条最右链(用的链式前向星,当然是最右了(雾))
k=rd();for(i=1;i<=k;++i) {a[i]=rd();in[a[i]]=1;}
sort(a+1,a+k+1,cmp);//按dfs序排序
sta[top=1]=1;
for(i=1;i<=k;++i){
t=LCA(a[i],sta[top]);
while(d[t]if(d[t]>=d[sta[top-1]]){
lk(t,sta[top--]);
if(sta[top]!=t) sta[++top]=t;
break;
}
lk(sta[top-1],sta[top]);top--;
}
if(sta[top]!=a[i]) sta[++top]=a[i];
}
for(;top>1;top--) lk(sta[top-1],sta[top]);//AddEdge
dp过程详见代码(懒)
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=2e6+50,inf=2e9;
int n,T,k,F[N][22],bin[22],MN,MX,df[N],d[N],a[N],dfn;
int fir[N],dir[N<<1],next[N<<1],nt,in[N],sta[N],top;
int head[N],to[N],nxt[N],w[N],mi[N],mx[N],sz[N],tot;
ll ans,sum[N];
char *TT,*mo,but[(1<<15)+2];
#define getchar() ((TT==mo && (mo=(TT=but)+fread(but,1,1<<15,stdin)),TT==mo)?0:*TT++)
inline int rd()
{
register char ch=getchar();register int x=0,f=1;
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
return x*f;
}
inline bool cmp(const int&x,const int&y){return df[x]inline void lkk(int u,int v)
{dir[++nt]=v;next[nt]=fir[u];fir[u]=nt;}
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=d[v]-d[u];}
inline int LCA(int x,int y)
{
if(d[y]>d[x]) swap(x,y);
register int t=d[x]-d[y],i;
for(i=0;bin[i]<=t;++i) if(bin[i]&t) x=F[x][i];
for(i=20;i>=0 && x!=y;--i)
if(F[x][i]!=F[y][i])
x=F[x][i],y=F[y][i];
return x==y?x:F[x][0];
}
inline void dfs(int x)
{
register int i,j;df[x]=++dfn;
for(i=1;bin[i]<=d[x];++i) F[x][i]=F[F[x][i-1]][i-1];
for(i=fir[x];i;i=next[i]){
if((j=dir[i])==F[x][0]) continue;
d[j]=d[x]+1;F[j][0]=x;
dfs(j);
}
}
inline void dfss(int x)
{
sz[x]=in[x];sum[x]=0;
mx[x]=in[x]? 0:-inf;mi[x]=in[x]? 0:inf;
for(register int j,i=head[x];i;i=nxt[i]){
j=to[i];dfss(j);
ans+=sum[j]*sz[x]+1ll*(sum[x]+1ll*w[i]*sz[x])*sz[j];
sz[x]+=sz[j];sum[x]+=sum[j]+1ll*sz[j]*w[i];
MN=min(MN,mi[x]+mi[j]+w[i]);
MX=max(MX,mx[x]+mx[j]+w[i]);
mi[x]=min(mi[x],w[i]+mi[j]);
mx[x]=max(mx[x],w[i]+mx[j]);
}
head[x]=0;
}
int main(){
register int i,j,ix,iy,t;
bin[0]=1;for(i=1;i<=20;++i) bin[i]=bin[i-1]<<1;
n=rd();
for(i=1;i1);
T=rd();
while(T--){
ans=0;tot=0;MX=-inf;MN=inf;
k=rd();for(i=1;i<=k;++i) {a[i]=rd();in[a[i]]=1;}
sort(a+1,a+k+1,cmp);
sta[top=1]=1;
for(i=1;i<=k;++i){
t=LCA(a[i],sta[top]);
while(d[t]if(d[t]>=d[sta[top-1]]){
lk(t,sta[top--]);
if(sta[top]!=t) sta[++top]=t;
break;
}
lk(sta[top-1],sta[top]);top--;
}
if(sta[top]!=a[i]) sta[++top]=a[i];
}
for(;top>1;top--) lk(sta[top-1],sta[top]);
dfss(1);
printf("%lld %d %d\n",ans,MN,MX);
for(i=1;i<=k;++i) in[a[i]]=0;
}
}