【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<<'\n';
}
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();
    }
}
posted @ 2019-03-12 11:01  Stargazer_cykoi  阅读(119)  评论(0编辑  收藏  举报