码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P4103 [HEOI2014]大工程

时间:2020-01-17 21:18:48      阅读:53      评论:0      收藏:0      [点我收藏+]

标签:algorithm   iostream   set   turn   for   math   time   etc   最小   

虚树+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

Luogu P4103 [HEOI2014]大工程

标签:algorithm   iostream   set   turn   for   math   time   etc   最小   

原文地址:https://www.cnblogs.com/Jackpei/p/12207388.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!