zoukankan      html  css  js  c++  java
  • 洛谷4103 HEOI2014大工程(虚树+dp)

    又是一道虚树好题啊

    我们建出来虚树,然后考虑dp过程,我们分别令(sum[x],mndis[x],mxdis[x],size[x])为子树内的路径长度和,最短链,最长链,子树内关键点个数。

    对于一个关键点,首先他的(size=1,mndis=0)

    我们考虑怎么合并,首先我们可以直接维护三个值表示最终的答案。如果说当前的点(size[x]>0),那么我们就可以每次用他和新的子树进行更新ans,然后合并
    QWQ
    其实合并就差不多类似的方式
    主要是(sum)合并的时候,你要用(size[x]*size[p]*val[i])当前这条边会被算的贡献,(size[x]*sum[p]),每条(p)的路径,都会到(x)中的所有关键点,(size[p]*sum[x])这个也是同理

    其他的应该也就差不多了

    直接上代码

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define mk makr_pair
    #define ll long long
    #define int long long
    using namespace std;
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    const int maxn = 3e6+1e2;
    const int maxm = 4e6+1e2;
    const int inf = 1e18;
    int point[maxn],nxt[maxm],to[maxm];
    int deep[maxn],dfn[maxn];
    int sum[maxn];
    int n,m,tot,top,cnt;
    int f[1010000][21];
    int k,size[maxn],tag[maxn];
    int s[maxn];
    int mxdis[maxn],mndis[maxn];
    int mx,mn,ymh;
    int a[maxn];
    int val[maxn];
    void addedge(int x,int y,int w)
    {
     //cout<<"***"<<" "<<x<<" "<<y<<endl;
     nxt[++cnt]=point[x];
     to[cnt]=y;
     val[cnt]=w;
     point[x]=cnt;
    }
    void dfs(int x,int fa,int dep)
    {
     deep[x]=dep;
     dfn[x]=++tot;
     for (int i=point[x];i;i=nxt[i])
     {
      int p = to[i];
      if (p==fa) continue;
      f[p][0]=x;
      dfs(p,x,dep+1);
     }
    }
    void init()
    {
     for (int j=1;j<=20;j++)
       for (int i=1;i<=n;i++)
         f[i][j]=f[f[i][j-1]][j-1];
    }
    int go_up(int x,int d)
    {
     for (int i=0;i<=20;i++)
     {
      if (d&(1<<i))
      {
       x=f[x][i];
      }
     }
     return x;
    }
    int lca(int x,int y)
    {
     if (deep[x]>deep[y]) x=go_up(x,deep[x]-deep[y]);
     else y=go_up(y,deep[y]-deep[x]);
     if (x==y) return x;
     for (int i=20;i>=0;i--)
     {
      if (f[x][i]!=f[y][i])
      {
       x=f[x][i];
       y=f[y][i];
      }
     }
     return f[x][0];
    }
    bool cmp(int a,int b)
    {
     return dfn[a]<dfn[b];
    }
    void solve()
    {
    // memset(point,0,sizeof(point));
     sort(a+1,a+1+k,cmp);
        cnt=0;
        top=1;
        s[top]=1;
        for (int i=1;i<=k;i++)
        {
         int l = lca(s[top],a[i]);
      if (l!=s[top])
      {
         while (top>1)
         {
            if (dfn[s[top-1]]>dfn[l])
            {
               addedge(s[top-1],s[top],deep[s[top]]-deep[s[top-1]]);
          top--; 
         }
         else
         {
           if (dfn[s[top-1]]==dfn[l])
           {
            addedge(s[top-1],s[top],deep[s[top]]-deep[s[top-1]]);
         top--;
         break;       
         }
         else
         {
          addedge(l,s[top],deep[s[top]]-deep[l]);
          s[top]=l;
          break;
         }
         }
         } 
      }
      if (s[top]!=a[i]) s[++top]=a[i]; 
     }
     while (top>1)
     {
      addedge(s[top-1],s[top],deep[s[top]]-deep[s[top-1]]);
      top--;
     }
    }
    void dp(int x,int flag)
    {
     mndis[x]=inf;
     mxdis[x]=0;
     size[x]=0;
     sum[x]=0;
     if (tag[x]==flag) 
     {
      size[x]=1;
      mndis[x]=0;
     }
     for (int &i=point[x];i;i=nxt[i])
     {
      int p = to[i];
      int now = val[i];
            dp(p,flag);
            if (size[x]>0)
            {
             ymh=ymh+size[p]*size[x]*now+size[p]*sum[x]+size[x]*sum[p];
             mx=max(mx,mxdis[x]+mxdis[p]+now);
             mn=min(mn,mndis[x]+mndis[p]+now);
      }
      mndis[x]=min(mndis[x],mndis[p]+now);
      mxdis[x]=max(mxdis[p]+now,mxdis[x]);
      sum[x]+=sum[p]+now*size[p]; 
      size[x]+=size[p];
     }
     //cout<<mndis[x]<<" "<<mxdis[x]<<" "<<size[x]<<" "<<sum[x]<<endl;
    }
    signed main()
    {
      n=read();
      for (int i=1;i<n;i++)
      {
        int x=read(),y=read();
        addedge(x,y,0);
        addedge(y,x,0);
      }
      dfs(1,0,1);
      init();
      memset(point,0,sizeof(point));
      m=read();
      for (int i=1;i<=m;i++)
      {
        ymh=0;
        mn=inf;
        mx=0;
        k=read();
        for (int j=1;j<=k;j++) a[j]=read(),tag[a[j]]=i;
        solve();
        dp(1,i);
        cout<<ymh<<" "<<mn<<" "<<mx<<"
    ";
      }
      return 0;
    }
    
    
  • 相关阅读:
    elk 搭建
    Web 开发规范 — WSGI
    Web 开发规范 — WSGI
    fastjson生成和解析json数据,序列化和反序列化数据
    第四章 字典
    Struts2 无后缀action请求
    字典和列表访问方式:
    第3章 使用字符串
    Struts2中的ModelDriven机制及其运用
    Struts2 的Action中取得请求参数值的几种方法
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161517.html
Copyright © 2011-2022 走看看