BZOJ3611: [Heoi2014]大工程

题解:虚树模板题 维护虚树 跑树dp即可

/**************************************************************
    Problem: 3611
    User: c20161007
    Language: C++
    Result: Accepted
    Time:15176 ms
    Memory:357336 kb
****************************************************************/
 
#include <bits/stdc++.h>
#define ll long long
const int MAXN=1e6+10;
using namespace std;
const ll inf=1e18;
vector<int>vec[MAXN];
int f[MAXN][21];ll sum[MAXN][21];int dep[MAXN];
int p[MAXN],cnt;
int st[MAXN],tot;
vector<int>V;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
void dfs(int v,int pre,int deep){
    dep[v]=deep;f[v][0]=pre;p[v]=++cnt;
    for(int i=0;i<vec[v].size();i++){
    int u=vec[v][i];
    if(u!=pre){
        sum[u][0]=1;
        dfs(u,v,deep+1);
    }
    }
}
void dfs1(int v){
    for(int i=1;i<=20;i++)sum[v][i]=sum[f[v][i-1]][i-1]+sum[v][i-1],f[v][i]=f[f[v][i-1]][i-1];
    for(int i=0;i<vec[v].size();i++){
    int u=vec[v][i];
    if(u!=f[v][0])dfs1(u);
    }
}
int Lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    int tmp=dep[u]-dep[v];
    for(int i=0;i<=20;i++)if(tmp&(1<<i))u=f[u][i];
    if(u==v)return u;
    for(int 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 built(int x){
    V.push_back(x);
    if(!tot){st[++tot]=x;return ;}
    int lca=Lca(x,st[tot]);
  //  cout<<lca<<" "<<x<<" "<<st[tot]<<endl;
    while(tot>1&&dep[lca]<dep[st[tot-1]]){
    vec[st[tot]].push_back(st[tot-1]);
    vec[st[tot-1]].push_back(st[tot]);
    tot--;
    }
    if(dep[st[tot]]>dep[lca]){
//  cout<<lca<<"::::"<<st[tot]<<endl;
    vec[st[tot]].push_back(lca);
    vec[lca].push_back(st[tot]);
    tot--;
    V.push_back(lca);
    }
   // cout<<tot<<"====="<<endl;
    if(!tot||dep[lca]>dep[st[tot]])st[++tot]=lca;
 //   cout<<st[tot]<<endl;
    st[++tot]=x;
}
ll dist(int u,int v){
    ll res=0;
   // cout<<u<<"::::::"<<v<<endl;
    for(int i=20;i>=0;i--){
    if(dep[f[u][i]]>dep[v]){
        res+=sum[u][i];
//      cout<<u<<"::::"<<f[u][i]<<" "<<res<<endl;
        u=f[u][i];
    }
    }
    res+=sum[u][0];
    return res;
}
ll _f[MAXN],__f[MAXN],d[MAXN],_d[MAXN];
int num[MAXN];
bool vis[MAXN];
ll ans;
int po;
void dfs(int x,int pre){
   // cout<<x<<" "<<pre<<endl;
    __f[x]=_d[x]=inf;_f[x]=d[x]=0;
    if(vis[x])num[x]=1;
    for(int i=0;i<vec[x].size();i++){
    if(vec[x][i]!=pre){
        dfs(vec[x][i],x);
        num[x]+=num[vec[x][i]];
        ll vul=dist(vec[x][i],x);
        ans+=1ll*vul*num[vec[x][i]]*(po-num[vec[x][i]]);
        if(d[vec[x][i]]||vis[vec[x][i]]){
        _f[x]=max(_f[x],d[x]+d[vec[x][i]]+vul);
        _f[x]=max(_f[x],_f[vec[x][i]]);
        d[x]=max(d[x],d[vec[x][i]]+vul);
        __f[x]=min(__f[x],__f[vec[x][i]]);
        __f[x]=min(__f[x],_d[x]+_d[vec[x][i]]+vul);
        _d[x]=min(_d[x],_d[vec[x][i]]+vul);
        if(vis[x])_f[x]=max(_f[x],d[vec[x][i]]+vul),__f[x]=min(__f[x],_d[vec[x][i]]+vul);
        }
    }
    }
    if(vis[x])_d[x]=0;
    if(!d[x])_d[x]=0;
}
int n,m;
bool cmp(int aa,int bb){return p[aa]<p[bb];}
int main(){
    n=read();int u,v;
    for(int i=1;i<n;i++)u=read(),v=read(),vec[u].push_back(v),vec[v].push_back(u);
   // cout<<"sb"<<endl;
    dfs(1,0,0);dfs1(1);int k;
    for(int i=1;i<=n;i++)vec[i].clear();
    m=read();
    for(int i=1;i<=m;i++){
    k=read();tot=0;ans=0;po=k;
    for(int i=1;i<=k;i++)v=read(),V.push_back(v),vis[v]=1;
    sort(V.begin(),V.end(),cmp);
    for(int i=1;i<=k;i++)built(V[i-1]);
//  for(int i=tot;i>=1;i--)cout<<st[i]<<" ";
//  cout<<endl;
    while(tot>1){vec[st[tot]].push_back(st[tot-1]),vec[st[tot-1]].push_back(st[tot]);tot--;}
//  cout<<vec[1].size()<<" "<<vec[4].size()<<" "<<vec[5].size()<<endl;
//  cout<<st[tot]<<endl;
    dfs(st[tot],f[st[tot]][0]);
    printf("%lld %lld %lld\n",ans,__f[st[tot]],_f[st[tot]]);
    //V.clear();
    for(int i=0;i<V.size();i++)vec[V[i]].clear(),vis[V[i]]=0,num[V[i]]=0;
    V.clear();
    }
    return 0;
}

 

3611: [Heoi2014]大工程

Time Limit: 60 Sec  Memory Limit: 512 MB
Submit: 2194  Solved: 945
[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
posted @ 2018-08-05 17:24  wang9897  阅读(105)  评论(0编辑  收藏  举报