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

    题目描述

    国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。

    我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。

    在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。

    现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少

    输入输出格式

    输入格式:

    第一行 n 表示点数。

    接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。点从 1 开始标号。

    接下来一行 q 表示计划数。对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。

    第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    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
    输出样例#1: 复制
    3 3 3 
    6 6 6 
    1 1 1 
    2 2 2 2 2 2

    说明

    对于第 1,2 个点: n<=10000

    对于第 3,4,5 个点: n<=100000,交通网络构成一条链

    对于第 6,7 个点: n<=100000

    对于第 8,9,10 个点: n<=1000000

    对于所有数据, q<=50000并且保证所有k之和<=2*n

    看到k的和小于2*n,于是立刻想到建虚树

    建出虚树后就dp

    size[x]表示x的子树中关键点数

    f[x]表示x子树中路径的贡献和

    Min[x]表示x子树中离x距离最小的关键点的距离

    Max[x]表示最大的距离

    最大值和求和很简单

    最大值总是要取到叶子节点,虚树中叶子节点总是关键点

    答案取当前Max[x]+Max[v]+边权w,然后Max[x]=max(Max[x],Max[v]+d)

    求和就考虑一条边的贡献

    一条边的贡献次数显然是size[v]*(k-size[v])

    所以f[x]+=f[v]+size[v]*(k-size[v])*w

    求最小值的话,Min[x]初值正无穷

    如果是关键点就直接取它的子树路径最小值,否则就是它的两个儿子的子树路径最小值相加

    如果是关键点,更新答案后Min[x]要清0,作为接下来的端点

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 typedef long long lol;
      8 const int N=2000005;
      9 struct Node
     10 {
     11     int next,to;
     12 }edge[N],edge2[N];
     13 int inf=1e9;
     14 int dep[N],fa[N][21],dfn[N],cnt,bin[25],head[N],head2[N],num,ed[N];
     15 int size[N],vis[N],Max[N],Min[N],k,M,ans1,ans2,n,Lca,a[N],s[N],top;
     16 lol f[N];
     17 int gi()
     18 {
     19     char ch=getchar();
     20     int x=0;
     21     while (ch<'0'||ch>'9') ch=getchar();
     22     while (ch>='0'&&ch<='9') 
     23     {
     24         x=x*10+ch-'0';
     25         ch=getchar();
     26     }
     27     return x;
     28 }
     29 bool cmp(int a,int b)
     30 {
     31     return dfn[a]<dfn[b];
     32 }
     33 void add(int u,int v)
     34 {
     35     num++;
     36     edge[num].next=head[u];
     37     head[u]=num;
     38     edge[num].to=v;
     39 }
     40 void add2(int u,int v)
     41 {
     42     if (u==v) return;
     43     num++;
     44     edge2[num].next=head2[u];
     45     head2[u]=num;
     46     edge2[num].to=v;
     47 }
     48 void dfs(int x,int pa)
     49 {int i;
     50     dep[x]=dep[pa]+1;
     51     dfn[x]=++cnt;
     52     for (i=1;bin[i]<=dep[x];i++)
     53     fa[x][i]=fa[fa[x][i-1]][i-1];
     54     for (i=head[x];i;i=edge[i].next)
     55     {
     56         int v=edge[i].to;
     57         if (v==pa) continue;
     58         fa[v][0]=x;
     59         dfs(v,x);
     60     }
     61     ed[x]=cnt;
     62 }
     63 int lca(int x,int y)
     64 {int as,i;
     65     if (dep[x]<dep[y]) swap(x,y);
     66     for (i=20;i>=0;i--)
     67     if (bin[i]<=dep[x]-dep[y])
     68     x=fa[x][i];
     69     if (x==y) return x;
     70     for (i=20;i>=0;i--)
     71     {
     72         if (fa[x][i]!=fa[y][i])
     73         {
     74             x=fa[x][i];y=fa[y][i];
     75         }
     76     }
     77     return fa[x][0];
     78 }
     79 
     80 void dp(int x)
     81 {int i;
     82     size[x]=vis[x];
     83     Max[x]=0;Min[x]=inf;f[x]=0;
     84     for (i=head2[x];i;i=edge2[i].next)
     85     {
     86         int v=edge2[i].to,d=dep[v]-dep[x];
     87         dp(v);
     88         size[x]+=size[v];
     89         f[x]+=f[v]+1ll*size[v]*(k-size[v])*d;
     90         ans1=min(ans1,Min[x]+Min[v]+d);Min[x]=min(Min[x],Min[v]+d);
     91         ans2=max(ans2,Max[x]+Max[v]+d);Max[x]=max(Max[x],Max[v]+d);
     92     }
     93     if (vis[x]) ans1=min(ans1,Min[x]),ans2=max(ans2,Max[x]),Min[x]=0;
     94 }
     95 int main()
     96 {int i,u,v,j,q;
     97  cin>>n;
     98  bin[0]=1;
     99  for (i=1;i<=20;i++)
    100  bin[i]=bin[i-1]*2;
    101   for (i=1;i<=n-1;i++)
    102    {
    103       scanf("%d%d",&u,&v);
    104       add(u,v);add(v,u);
    105    } 
    106    dfs(1,0);
    107    cin>>q;
    108    while (q--)
    109    {
    110         k=gi();
    111      M=k;
    112         num=0;ans1=inf;ans2=0;
    113         for (i=1;i<=k;i++)
    114           a[i]=gi(),vis[a[i]]=1;
    115         sort(a+1,a+k+1,cmp);
    116         Lca=a[1];
    117      for (i=2;i<=k;i++)
    118        if (ed[a[i-1]]<dfn[a[i]])
    119        a[++M]=lca(a[i-1],a[i]),Lca=lca(Lca,a[i]);
    120        a[++M]=Lca;
    121        sort(a+1,a+M+1,cmp);
    122        M=unique(a+1,a+M+1)-a-1;
    123        s[++top]=a[1];
    124        for (i=2;i<=M;i++)
    125        {
    126            while (top&&ed[s[top]]<dfn[a[i]]) top--;
    127            add2(s[top],a[i]);
    128            s[++top]=a[i];
    129        } 
    130        dp(Lca);
    131        printf("%lld %d %d
    ",f[Lca],ans1,ans2);
    132         for (i=1;i<=M;i++)
    133         vis[a[i]]=head2[a[i]]=0;
    134    }
    135 }
  • 相关阅读:
    WIN10 UBUNTU 异常:sleep: cannot read realtime clock: Invalid argument
    Mysql表名大小写忽略
    Spring boot自定义配置文件并映射到指定类中
    list addAll产生异常java.lang.UnsupportedOperationException
    Oracle extract函数提取时分秒的问题
    JOOQ默认schema
    Druid数据库连接失败,无限尝试问题
    Mysql安装后root无法登陆(Access denied for user 'root'@'localhost')
    JavaSE第17篇:集合之Map集合
    JavaSE第16篇:集合之Collection集合下篇
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8454972.html
Copyright © 2011-2022 走看看