• 【HEOI2014】大工程


    题面

    虚树+贡献

    题解

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #define ri register int
    #define N 1000050
    #define ll long long
    using namespace std;
    int n,q,m,cnt;
    int a[2*N],yy[2*N],top;
    int f[N][21],dep[N];
    bool vis[N],imp[N];
    int s;
    ll sumdis,maxdis,mindis;
    
    vector<int> to[N];
    
    vector<int> son[N];
    int siz[N],maxc[N],minc[N],nsmin[N];
    
    int dfin[N],dfou[N];
    
    void dfs(int x,int ff,int d) {
      f[x][0]=ff; dep[x]=d;
      for (ri i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];
      dfin[x]=++cnt;
      for (ri i=to[x].size()-1;i>=0;i--) if (to[x][i]!=ff) dfs(to[x][i],x,d+1);
      dfou[x]=++cnt;
    }
    
    bool cmp1(int x,int y){
      return dfin[x]<dfin[y];
    }
    
    bool cmp2(int x,int y){
      int key1,key2;
      if (x>0) key1=dfin[x]; else key1=dfou[-x];
      if (y>0) key2=dfin[y]; else key2=dfou[-y];
      return key1<key2;
    }
    
    int lca(int u,int v){
      if (dep[u]<dep[v]) swap(u,v);
      for (ri i=20;i>=0;i--) if (dep[f[u][i]]>=dep[v]) u=f[u][i];
      if (u==v) return u;
      for (ri i=20;i>=0;i--) if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
      return f[u][0];
    }
    
    void dp(int x) {
      if (imp[x]) siz[x]=1,minc[x]=0,maxc[x]=0; else siz[x]=0,minc[x]=7654321,maxc[x]=-7654321;
      nsmin[x]=7654321;
      for (ri i=son[x].size()-1;i>=0;i--) {
        dp(son[x][i]);
        siz[x]+=siz[son[x][i]];
        if (minc[son[x][i]]+dep[son[x][i]]-dep[x]<nsmin[x]) nsmin[x]=minc[son[x][i]]+dep[son[x][i]]-dep[x];
        if (minc[son[x][i]]+dep[son[x][i]]-dep[x]<minc[x]) minc[x]=minc[son[x][i]]+dep[son[x][i]]-dep[x];
        if (maxc[son[x][i]]+dep[son[x][i]]-dep[x]>maxc[x]) maxc[x]=maxc[son[x][i]]+dep[son[x][i]]-dep[x];
      }
    }
    
    void dp2(int x) {
      for (ri i=son[x].size()-1;i>=0;i--) dp2(son[x][i]);
      if (imp[x]) {
        if (maxc[x]>maxdis) maxdis=maxc[x];
        if (nsmin[x]<mindis) mindis=nsmin[x];
      }
      int s1=-7654321,s2=-7654321,b1=7654321,b2=7654321;
      for (ri i=son[x].size()-1;i>=0;i--) {
        maxc[son[x][i]]+=(dep[son[x][i]]-dep[x]);
        minc[son[x][i]]+=(dep[son[x][i]]-dep[x]);
        sumdis+=(siz[s]-siz[son[x][i]])*1LL*(siz[son[x][i]])*1LL*(dep[son[x][i]]-dep[x]);
        if (maxc[son[x][i]]>s1) s2=s1,s1=maxc[son[x][i]];else if (maxc[son[x][i]]>s2) s2=maxc[son[x][i]];
        if (minc[son[x][i]]<b1) b2=b1,b1=minc[son[x][i]];else if (minc[son[x][i]]<b2) b2=minc[son[x][i]];
      }
      if (s1+s2>maxdis) maxdis=s1+s2;
      if (b1+b2<mindis) mindis=b1+b2;
    }
    
    void view(int cur,int x){
      cout<<cur<<" "<<x<<endl;
      for (ri i=son[x].size()-1;i>=0;i--) cout<<son[x][i]<<" "; cout<<endl;
    }
    
    int main(){
      scanf("%d",&n);
      int u,v;
      for (ri i=1;i<n;i++) {
        scanf("%d %d",&u,&v);
        to[u].push_back(v);
        to[v].push_back(u);
      }
      cnt=0;
      dfs(1,1,1);
      scanf("%d",&q);
      for (ri ti=1;ti<=q;ti++) {
        scanf("%d",&m); 
        for (ri i=1;i<=m;i++) {
          scanf("%d",&a[i]);
          vis[a[i]]=1;
          imp[a[i]]=1;
        }
        sort(a+1,a+m+1,cmp1);
        cnt=m;
        for (ri i=1;i<m;i++) {
          int t=lca(a[i],a[i+1]);
          if (!vis[t]) vis[t]=1,a[++cnt]=t;
        }
        int cnt2=cnt;
        for (ri i=1;i<=cnt;i++) {
          a[++cnt2]=-a[i];
        }
        sort(a+1,a+cnt2+1,cmp2);
        //stack<int> yy;
        //while (!yy.empty()) yy.pop();
        top=0;
        for (ri i=1;i<=cnt2;i++) if (a[i]>0) yy[++top]=a[i];
        else {
          top--;
          if (top>0) son[yy[top]].push_back(-a[i]);
          else s=-a[i];
        }
        sumdis=0; maxdis=0; mindis=987654321;
        dp(s); dp2(s);
        printf("%lld %lld %lld
    ",sumdis,mindis,maxdis);
        for (ri i=1;i<=cnt2;i++) if (a[i]>0) vis[a[i]]=0,imp[a[i]]=0,son[a[i]].clear();
      }
    }
  • 相关阅读:
    c++的一些个学习及总结
    简单回合制游戏流程
    c++11 符号修饰与函数签名、函数指针、匿名函数、仿函数、std::function与std::bind
    二叉搜索树、平衡二叉树、红黑树
    STL之空间配置器
    centos 7 安装mysql及常用操作
    生产服务器问题定位
    Linux常用命令
    Garbage First(G1) 垃圾收集器
    垃圾回收算法和垃圾收集器
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11423896.html
Copyright © 2020-2023  润新知