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

    像这种询问很多但是每个询问的关键点数都不多的题大多数都要用到虚树。

    虚树就是只含关键点和关键点在原树中的LCA的新构造的树。

    然后建完虚树就可以直接dp了(虚树模板+树上dp模板)

    不过写起来挺劲的hhhh,又调了好久(为什么最近总是把数组下标和权值搞混gg)

    (可能今天写了一天数据结构比较蛋疼hhhh)

    /**************************************************************
        Problem: 3611
        User: JYYHH
        Language: C++
        Result: Accepted
        Time:7872 ms
        Memory:203356 kb
    ****************************************************************/
     
    #include<bits/stdc++.h>
    #define ll long long
    #define maxn 1000005
    #define pb push_back
    using namespace std;
    vector<int> g[maxn];
    bool ispt[maxn];
    int to[maxn],ne[maxn],mxl,mnl;
    int hd[maxn],num,n,d[maxn],sz[maxn];
    int len,que[maxn],dc=0,q,vis[maxn];
    int st[maxn],tp,dfn[maxn],f[maxn][23];
    int mn[maxn],mx[maxn],ci[30];
    ll tot[maxn],tt;
     
    inline bool cmp(int x,int y){
        return dfn[x]<dfn[y];
    }
     
    inline void add(int x,int y){
        to[++num]=y,ne[num]=hd[x],hd[x]=num;
    }
     
    inline int read(){
        int x=0; char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x;
    }
     
    void dfs(int x,int fa){
        int to; dfn[x]=++dc;
         
        for(int i=1;ci[i]<=d[x];i++) f[x][i]=f[f[x][i-1]][i-1];
         
        for(int i=g[x].size()-1;i>=0;i--){
            to=g[x][i];
            if(to==fa) continue;
            d[to]=d[x]+1,f[to][0]=x;
            dfs(to,x);
        }
    }
     
    inline int LCA(int a,int b){
        if(d[a]<d[b]) swap(a,b);
        int dt=d[a]-d[b];
        for(int i=0;ci[i]<=dt;i++) if(ci[i]&dt) a=f[a][i];
         
        if(a==b) return a;
         
        int s=log(d[a])/log(2)+1;
        for(;s>=0;s--){
            if(ci[s]>d[a]) continue;
            if(f[a][s]!=f[b][s]) a=f[a][s],b=f[b][s];
        }
         
        return f[a][0];
    }
     
    inline void clear(int x){
        hd[x]=sz[x]=tot[x]=0;
    }
     
    void dp(int x){
        if(ispt[x]){
            sz[x]=1,mn[x]=mx[x]=0;
        }else mn[x]=1<<25,mx[x]=-1<<25;
         
        for(int i=hd[x];i;i=ne[i]){
            dp(to[i]);
            int lgh=d[to[i]]-d[x];
            mxl=max(mxl,mx[x]+mx[to[i]]+lgh),mx[x]=max(mx[x],mx[to[i]]+lgh);
            mnl=min(mnl,mn[x]+mn[to[i]]+lgh),mn[x]=min(mn[x],mn[to[i]]+lgh);
            tt+=(ll)sz[to[i]]*sz[x]*(ll)lgh+(ll)sz[x]*tot[to[i]]+(ll)sz[to[i]]*tot[x];
            tot[x]+=(ll)tot[to[i]]+sz[to[i]]*(ll)lgh;   
            sz[x]+=sz[to[i]];   
        }
         
    //  printf("%d %d %d %lld
    ",x,mn[x],mx[x],tot[x]);
    }
     
    inline void solve(){
        sort(que+1,que+len+1,cmp);
        st[tp=1]=1,num=0,vis[1]=q,clear(1);
         
        for(int i=1;i<=len;i++){
            ispt[que[i]]=1;
            if(que[i]==1) continue;
            if(vis[que[i]]!=q) vis[que[i]]=q,clear(que[i]);
             
            int la=LCA(que[i],st[tp]);
            if(la!=st[tp]){
                if(vis[la]!=q) vis[la]=q,clear(la);
                 
                while(tp>1&&d[st[tp-1]]>=d[la]) tp--,add(st[tp],st[tp+1]);
                if(st[tp]!=la) add(la,st[tp]),st[tp]=la;
            }
             
            st[++tp]=que[i];
        }
         
        for(;tp>1;tp--) add(st[tp-1],st[tp]);
        dp(1);
         
        for(int i=1;i<=len;i++) ispt[que[i]]=0;
    }
     
    int main(){
        ci[0]=1;
        for(int i=1;i<=23;i++) ci[i]=ci[i-1]+ci[i-1];
         
        n=read();
        int uu,vv;
        for(int i=1;i<n;i++){
            uu=read(),vv=read();
            g[uu].pb(vv),g[vv].pb(uu);
        }
        d[1]=0,f[1][0]=1;
        dfs(1,1);
         
        q=read();
        while(q--){
            tt=0,mxl=0,mnl=1<<30;
             
            len=read();
            for(int i=1;i<=len;i++) que[i]=read();
            solve();
            printf("%lld %d %d
    ",tt,mnl,mxl);
        }
         
        return 0;
    }
  • 相关阅读:
    Scilab5.5.2 在Centos5.11下binary安装(注:不是源码编译安装)
    《DSP using MATLAB》Problem 9.5
    Java 出现警告 不能读取AppletViewer的属性文件
    《DSP using MATLAB》Problem 9.4
    《DSP using MATLAB》Problem 9.2
    《DSP using MATLAB》Problem 8.46
    《DSP using MATLAB》Problem 8.45
    风力摆?这是不是太简单了点
    树莓派:基于物联网做的指纹打卡器
    Python之面向对象(一)
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8318577.html
Copyright © 2011-2022 走看看