1. 程式人生 > >[HEOI2014]大工程

[HEOI2014]大工程

dep heoi2014 現在 更新 main swap reg 很多 uniq

題目描述

國家有一個大工程,要給一個非常大的交通網絡裏建一些新的通道。

我們這個國家位置非常特殊,可以看成是一個單位邊權的樹,城市位於頂點上。

在 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\n",f[Lca],ans1,ans2);
132         for (i=1;i<=M;i++)
133         vis[a[i]]=head2[a[i]]=0;
134    }
135 }

[HEOI2014]大工程