zoukankan      html  css  js  c++  java
  • [Heoi2014]大工程

    
    
    

    3611: [Heoi2014]大工程

    Time Limit: 60 Sec  Memory Limit: 512 MB
    Submit: 1331  Solved: 577
    [Submit][Status][Discuss]

    Description

    国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。 
    我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。 
    在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。
     现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。
    现在对于每个计划,我们想知道:
     1.这些新通道的代价和
     2.这些新通道中代价最小的是多少 
    3.这些新通道中代价最大的是多少

    Input

    第一行 n 表示点数。

     接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。
    点从 1 开始标号。 接下来一行 q 表示计划数。
    对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。
     第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。

    Output

    输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。 

     

    Sample Input

    10
    2 1
    3 2
    4 1
    5 2
    6 4
    7 5
    8 6
    9 7
    10 9
    5
    2
    5 4
    2
    10 4
    2
    5 2
    2
    6 1
    2
    6 1

    Sample Output

    3 3 3
    6 6 6
    1 1 1
    2 2 2
    2 2 2

    HINT

    n<=1000000 


    q<=50000并且保证所有k之和<=2*n
     
    虚树DP
    先是总和,设sum[i]表示以i为根的子树中的路径总和
    sum[i]+=sum[u]+size[u]*(k-size[u])*dd代表路径长度,k代表询问点总数。可以看出这个式子根i这个点是否是询问点没有关系。
    因为不管这个点是否是询问点,他的子树中的每个点都要和其他的点组合,根据乘法原理,答案就是这个了,
    但若这个点是询问点,那么还要统计其他点到这个点的距离,这里没有统计,但是在递归处理这个点的子树的时候会统计到的。
    最大值和最小值类似zd[i]代表i的子树中到i最远的点的距离,ans1=max(ans1,zd[i]+zd[u]+d),

    注意先算答案再更新值,zd[i]=max(zd[i],zd[u]+d)。若这个点是询问点,还要算ans1=max(ans1,zd[x])。最小值类似。
    还有,虚树的根要算,不能默认为1,虚树的根为LCA(所有的询问点)
      1 #include <algorithm>
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #define maxn 1000010
      8 #define inf 1999999999
      9 #define LL long long
     10 #define RG register
     11 using namespace std;
     12 struct data{
     13   int nex,to;
     14 }e[maxn*2],g[maxn*2];
     15 int head[maxn],edge=0,a[maxn],dis[maxn],dfn[maxn],head1[maxn],edge1=0,n;
     16 LL sum[maxn],zd[maxn],zx[maxn];
     17 LL size[maxn],k,ans1,ans2,s[maxn];
     18 bool bj[maxn];
     19 int f[maxn][20];
     20 inline void add(int from,int to){
     21   e[++edge].nex=head[from];
     22   e[edge].to=to;
     23   head[from]=edge;
     24 }
     25 inline void link(int from,int to){
     26   if(from==to) return;
     27   g[++edge1].nex=head1[from];
     28   g[edge1].to=to;
     29   head1[from]=edge1;
     30 }
     31 int de=0;
     32 void dfs(int x,int fa){
     33   de++;
     34   dfn[x]=de;
     35   for(int i=head[x];i;i=e[i].nex){
     36     int u=e[i].to;
     37     if(u==fa) continue;
     38     f[u][0]=x;
     39     dis[u]=dis[x]+1;
     40     dfs(u,x);
     41   }
     42 }
     43 inline int lca(int x,int y){
     44   if(dis[x]<dis[y]) swap(x,y);
     45   for(int i=18;i>=0;i--)
     46     if(dis[f[x][i]]>=dis[y]) x=f[x][i];
     47   if(x==y) return x;
     48   for(int i=18;i>=0;i--)
     49     if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
     50   return f[x][0];
     51 }
     52 bool cmp(const int a,const int b){
     53   return dfn[a]<dfn[b];
     54 }
     55 void DP(int x,int fa){
     56   size[x]=bj[x];
     57   zd[x]=0,zx[x]=inf;
     58   sum[x]=0;
     59   for(RG int i=head1[x];i;i=g[i].nex){
     60     int u=g[i].to;
     61     if(u==fa) continue;
     62     DP(u,x);LL d=dis[u]-dis[x];
     63     size[x]+=size[u];
     64     sum[x]+=sum[u]+size[u]*(k-size[u])*d;
     65     ans1=min(ans1,zx[x]+zx[u]+d),zx[x]=min(zx[x],zx[u]+d);
     66     ans2=max(ans2,zd[x]+zd[u]+d),zd[x]=max(zd[x],zd[u]+d);
     67   }
     68   if(bj[x]) ans1=min(ans1,zx[x]),ans2=max(ans2,zd[x]),zx[x]=0;
     69   head1[x]=0;bj[x]=0;
     70   return;
     71 }
     72 inline void build(){
     73   int top=0,LCA;
     74   scanf("%lld",&k);
     75   for(RG int i=1;i<=k;i++)scanf("%d",&a[i]),bj[a[i]]=1;
     76   sort(a+1,a+k+1,cmp);
     77   LCA=lca(a[1],a[2]);
     78   for(RG int i=3;i<=k;i++)
     79     LCA=lca(LCA,a[i]);
     80   int root=LCA;
     81   for(RG int i=1;i<=k;i++){
     82     if(top==0){s[++top]=a[i];continue;}
     83     LCA=lca(s[top],a[i]);
     84     while(1){
     85       if(dis[s[top-1]]<=dis[LCA]){
     86     link(s[top],LCA),link(LCA,s[top]);
     87     top--;
     88     if(s[top]!=LCA) s[++top]=LCA;
     89     break;
     90       }
     91       link(s[top],s[top-1]),link(s[top-1],s[top]),top--;
     92     }
     93     if(s[top]!=a[i]) s[++top]=a[i];
     94   }
     95   while(top>1) link(s[top],s[top-1]),link(s[top-1],s[top]),top--;
     96   top--;
     97   ans1=inf,ans2=0;
     98   DP(root,0);
     99   printf("%lld %lld %lld
    ",sum[root],ans1,ans2);
    100   edge1=0;
    101 }
    102 int main()
    103 {
    104   freopen("!.in","r",stdin);
    105   freopen("!.out","w",stdout);
    106   int qes,x,y;
    107   scanf("%d",&n);
    108   for(RG int i=1;i<n;i++)
    109     scanf("%d%d",&x,&y),add(x,y),add(y,x);
    110   dis[1]=1;
    111   f[1][0]=1;
    112   dfs(1,0);
    113   for(RG int i=1;i<=18;i++)
    114     for(RG int j=1;j<=n;j++)
    115       f[j][i]=f[f[j][i-1]][i-1];
    116   scanf("%d",&qes);
    117   for(RG int i=1;i<=qes;i++)
    118     build();
    119   return 0;
    120 }
    
    
    
     
  • 相关阅读:
    商业智能领域需要了解的数据库优化理论
    动态监听与静态监听(转载)
    Oracle查看表结构的几种方法
    PLSQL Developer使用技巧整理
    Oracle数据库的三种验证机制
    EAV模型
    三门问题
    第一个python实例程序
    type()
    pi
  • 原文地址:https://www.cnblogs.com/pantakill/p/6708418.html
Copyright © 2011-2022 走看看