zoukankan      html  css  js  c++  java
  • 【BZOJ3611】【HeOI2014】—大工程(虚树+dp)

    传送门

    首先肯定建出虚树
    考虑三种答案如何分别统计

    路径长度和显然示是对于每条边考虑一下上下有多少个点,乘一下就可以了
    最大值显然就是树的直径
    最小值可以考虑树形dpdp,考虑mn[i]mn[i]表示ii到其子树中最近的距离
    显然可以类似直径树形dpdp解决

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=1000005;
    const ll inf=1e9;
    namespace T{
        int adj[N],nxt[N<<1],to[N<<1],cnt,siz[N],dfn[N],tot,son[N],top[N],fa[N],dep[N];
        inline void addedge(int u,int v){
            nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
        }
        void dfs1(int u){
            siz[u]=1;
            for(int e=adj[u];e;e=nxt[e]){
                int v=to[e];
                if(v==fa[u])continue;
                fa[v]=u,dep[v]=dep[u]+1;
                dfs1(v),siz[u]+=siz[v];
                if(siz[v]>siz[son[u]])son[u]=v;
            }
        }
        void dfs2(int u,int tp){
            dfn[u]=++tot,top[u]=tp;
            if(son[u])dfs2(son[u],tp);
            for(int e=adj[u];e;e=nxt[e]){
                int v=to[e];
                if(v==fa[u]||v==son[u])continue;
                dfs2(v,v);
            }
        }
        inline int Lca(int u,int v){
            while(top[u]!=top[v]){
                if(dep[top[u]]<dep[top[v]])swap(u,v);
                u=fa[top[u]];
            }
            return dep[u]>dep[v]?v:u;
        }
    };
    int n,adj[N],nxt[N<<1],to[N<<1],cnt,q,a[N],stk[N],top,k,vis[N],siz[N],ans2,ans3,mx[N],mn[N];
    ll ans1;
    inline void addedge(int u,int v){
        nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    }
    inline bool comp(const int &a,const int &b){
        return T::dfn[a]<T::dfn[b];
    }
    inline void chemn(int &a,int b){
        a=a>b?b:a;
    }
    inline void chemx(int &a,int b){
        a=a>b?a:b;
    }
    void dp(int u){
        mx[u]=0,mn[u]=inf,siz[u]=vis[u];
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            int d=T::dep[v]-T::dep[u];
            dp(v),siz[u]+=siz[v];
            ans1+=1ll*siz[v]*(k-siz[v])*d;
            chemn(ans2,mn[u]+mn[v]+d),chemn(mn[u],mn[v]+d);
            chemx(ans3,mx[u]+mx[v]+d),chemx(mx[u],mx[v]+d);
        }
        if(vis[u])chemn(ans2,mn[u]),chemx(ans3,mx[u]),mn[u]=0;
        adj[u]=0;
    }
    inline void work(){
        top=0,cnt=0;
        for(int i=1;i<=k;i++){
            if(!top){stk[++top]=a[i];continue;}
            int lca=T::Lca(stk[top],a[i]);
            while(T::dfn[lca]<T::dfn[stk[top]]){
                if(T::dfn[lca]>=T::dfn[stk[top-1]]){
                    addedge(lca,stk[top]);
                    if(stk[--top]!=lca)stk[++top]=lca;
                    break;
                }
                addedge(stk[top-1],stk[top]),top--;
            }
            stk[++top]=a[i];
        }
        while(top>1)addedge(stk[top-1],stk[top]),top--;
        ans1=0,ans2=inf,ans3=0,dp(stk[1]);
        for(int i=1;i<=k;i++)vis[a[i]]=0;
        cout<<ans1<<" "<<ans2<<" "<<ans3<<'
    ';
    }
    int main(){
        n=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            T::addedge(u,v),T::addedge(v,u);
        }
        T::dfs1(1),T::dfs2(1,1);
        q=read();
        for(int i=1;i<=q;i++){
            k=read();
            for(int j=1;j<=k;j++)a[j]=read(),vis[a[j]]=1;
            sort(a+1,a+k+1,comp),work();
        }
    }
    
  • 相关阅读:
    Linux 下用 Python 连接 MSSql Server 2008
    这周我加星(4)
    几个受益终身的英文缩写
    这周我加星(1)
    证据
    这周我加星(3)
    代友招人────3D 客户端程序员
    人在广州,力撑陈 Sir
    谁不会成为 Linux(ubuntu)的用户
    这周我加星(5)
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145614.html
Copyright © 2011-2022 走看看