码迷,mamicode.com
首页 > 其他好文 > 详细

[HEOI2014]大工程

时间:2019-01-10 13:15:00      阅读:144      评论:0      收藏:0      [点我收藏+]

标签:main   type   有一个   ||   wol   getchar   cstring   tchar   putc   

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
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

先吐槽一句:这个样例真良心

标记点个数与\(n\)同阶?上虚树!建出虚树后考虑求解答案,权值和二次换根即可,最大最小值在dfs的时候记录最大次大,最小次小,然后更新即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1; char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=1e6;
int ID[N+10];
bool cmp(int x,int y){return ID[x]<ID[y];}
struct S1{
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,Time;
    int size[N+10],top[N+10],fa[N+10],deep[N+10],Rem[N+10];
    void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
    void insert(int x,int y){join(x,y),join(y,x);}
    void build(int x){
        deep[x]=deep[fa[x]]+1,size[x]=1;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]) continue;
            fa[son]=x,build(son);
            size[x]+=size[son];
            if (size[Rem[x]]<size[son]) Rem[x]=son;
        }
    }
    void dfs(int x){
        if (!x) return;
        ID[x]=++Time;
        top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
        dfs(Rem[x]);
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==Rem[x]||son==fa[x])    continue;
            dfs(son);
        }
    }
    int LCA(int x,int y){
        while (top[x]!=top[y]){
            if (deep[top[x]]<deep[top[y]])  swap(x,y);
            x=fa[top[x]];
        }
        return deep[x]<deep[y]?x:y;
    }
    int dis(int x,int y){return abs(deep[x]-deep[y]);}
}HLD;//Heavy Light Decomposition
struct S2{
    struct node{
        int Mx,Sx;
        int Mn,Sn;
        node(){Mx=Sx=-inf,Mn=Sn=inf;}
        void clear(){Mx=Sx=-inf,Mn=Sn=inf;}
        void init(){Mx=Mn=0;}
    }f[N+10];
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],val[(N<<1)+10];
    bool mark[N+10];
    int size[N+10],A[N+10],stack[N+10];
    int tot,Max,Min,All; ll Ans;
    void updata(node &x,node y,int v){
        node z=y; z.Mx+=v,z.Mn+=v;
        if (x.Mx<z.Mx)  x.Sx=x.Mx,x.Mx=z.Mx;
        else    if (x.Sx<z.Mx)  x.Sx=z.Mx;
        
        if (x.Mn>z.Mn)  x.Sn=x.Mn,x.Mn=z.Mn;
        else    if (x.Sn>z.Mn)  x.Sn=z.Mn;
    }
    void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
    void insert(int x,int y){insert(x,y,HLD.dis(x,y));}
    void rebuild(int m){
        int top=0; tot=0;
        sort(A+1,A+1+m,cmp);
        stack[++top]=1;
        for (int i=1;i<=m;i++){
            int x=A[i],lca=HLD.LCA(stack[top],x);
            if (x==1)   continue;
            if (lca==stack[top]){
                stack[++top]=x;
                continue;
            }
            while (true){
                int y=stack[top-1];
                if (ID[y]>=ID[lca]){
                    insert(stack[top--],y);
                    continue;
                }else{
                    if (lca==stack[top])    break;
                    insert(stack[top],lca);
                    stack[top]=lca; break;
                }
            }
            stack[++top]=x;
        }
        while (top>1){
            insert(stack[top],stack[top-1]);
            top--;
        }
    }
    void dfs(int x,int fa){
        f[x].clear(); size[x]=mark[x];
        if (mark[x])    f[x].init();
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa)    continue;
            dfs(son,x),size[x]+=size[son];
            updata(f[x],f[son],val[p]);
        }
        Max=max(Max,f[x].Mx+f[x].Sx);
        Min=min(Min,f[x].Mn+f[x].Sn);
    }
    void sum(int x,int fa){
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa)    continue;
            sum(son,x);
            Ans+=1ll*size[son]*(All-size[son])*val[p];
        }
        now[x]=0;
    }
    void work(){
        int m=read();
        for (int i=1;i<=m;i++)  mark[A[i]=read()]=1;
        rebuild(m),Max=-inf,Min=inf;
        dfs(1,0),All=size[1],Ans=0,sum(1,0);
        printf("%lld %d %d\n",Ans,Min,Max);
        for (int i=1;i<=m;i++)  mark[A[i]]=0;
    }
}T;
int main(){
    int n=read();
    for (int i=1;i<n;i++){
        int x=read(),y=read();
        HLD.insert(x,y);
    }
    HLD.build(1),HLD.dfs(1);
    int m=read();
    for (int i=1;i<=m;i++)  T.work();
    return 0;
}

[HEOI2014]大工程

标签:main   type   有一个   ||   wol   getchar   cstring   tchar   putc   

原文地址:https://www.cnblogs.com/Wolfycz/p/10249082.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!