• P4103[HEOI2014]大工程 (虚树)


    观察数据范围是跟k有关的,因此我们考虑建立虚树,对于维护三个值

    总和就是常规的按每条路左右两边点数算贡献,注意是特殊点的数量

    之后我们维护mi[i],mx[i]表示对于当前点,子树中离他最近的特殊点在哪

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<ll,ll> pll;
    const int N=2e6+10;
    const int M=2e6+10;
    const int inf=0x3f3f3f3f;
    const ll mod=998244353;
    struct node{
        int x;
        ll w;
    };
    vector<node> g[N],g1[N];
    int dfn[N],times,depth[N];
    int n,f[N][25],cost[N][25];
    int st[N];
    int cnt[N];
    ll sz[N];
    int q[N],k;
    ll dp[N][2],sum,mi,mx;
    ll ans1[N],ans2[N];
    void dfs(int u,int fa,ll w){
        dfn[u]=++times;
        depth[u]=depth[fa]+1;
        f[u][0]=fa,cost[u][0]=w;
        int i;
        for(i=1;i<=21;i++){
            f[u][i]=f[f[u][i-1]][i-1];
            cost[u][i]=cost[f[u][i-1]][i-1]+cost[u][i-1];
        }
        for(i=0;i<g1[u].size();i++){
            int v=g1[u][i].x;
            if(v==fa)
                continue;
            dfs(v,u,g1[u][i].w);
        }
    }
    bool cmp(int a,int b){
        return dfn[a]<dfn[b];
    }
    int lca(int a,int b){
        if(depth[a]<depth[b])
            swap(a,b);
        int i;
        for(i=21;i>=0;i--){
            if(depth[f[a][i]]>=depth[b]){
                a=f[a][i];
            }
        }
        if(a==b)
            return a;
        for(i=21;i>=0;i--){
            if(f[a][i]!=f[b][i]){
                a=f[a][i];
                b=f[b][i];
            }
        }
        return f[a][0];
    }
    ll query(int a,int b){
        ll ans=0;
        if(depth[a]>depth[b])
            swap(a,b);
        for(int i=21;i>=0;i--){
            if(depth[f[b][i]]>=depth[a]){
                ans+=cost[b][i];
                b=f[b][i];
            }
        }
        return ans;
    }
    void add(int a,int b){
        ll num=query(a,b);
        g[a].push_back({b,num});
    }
    void get(int u,int fa){
        int i;
        if(st[u]){
           sz[u]=1;
           ans1[u]=ans2[u]=0;
        }
        else{
            ans1[u]=inf,ans2[u]=-inf,sz[u]=0;
        }
        for(i=0;i<g[u].size();i++){
            int v=g[u][i].x;
            if(v==fa)
                continue;
            get(v,u);
            sum+=sz[v]*(k-sz[v])*g[u][i].w;
            sz[u]+=sz[v];
            mi=min(mi,ans1[u]+g[u][i].w+ans1[v]);
            mx=max(mx,ans2[u]+g[u][i].w+ans2[v]);
            ans1[u]=min(ans1[u],g[u][i].w+ans1[v]);
            ans2[u]=max(ans2[u],g[u][i].w+ans2[v]);
            st[v]=0;
        }
        g[u].clear();
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n;
        int i;
        for(i=1;i<n;i++){
            int a,b;
            cin>>a>>b;
            g1[a].push_back({b,1});
            g1[b].push_back({a,1});
        }
        dfs(1,0,0);
        int m;
        cin>>m;
        while(m--){
            cin>>k;
            for(i=1;i<=k;i++){
                int x;
                cin>>x;
                st[x]=1;
                cnt[i]=x;
            }
            sort(cnt+1,cnt+1+k,cmp);
            q[1]=1;
            int tt=1;
            for(i=1;i<=k;i++){
                if(cnt[i]==1)
                    continue;
                int p=lca(cnt[i],q[tt]);
                if(p!=q[tt]){
                    while(dfn[p]<dfn[q[tt-1]]){
                        add(q[tt-1],q[tt]);
                        tt--;
                    }
                    if(dfn[p]!=dfn[q[tt-1]]){
                        add(p,q[tt]);
                        q[tt]=p;
                    }
                    else{
                        add(p,q[tt]);
                        tt--;
                    }
                }
                q[++tt]=cnt[i];
            }
            for(i=1;i<tt;i++){
                add(q[i],q[i+1]);
            }
            sum=0,mi=1e18,mx=-1e18;
            get(1,-1);
            cout<<sum<<" "<<mi<<" "<<mx<<endl;
            st[1]=0;
        }
        return 0;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    linux软件必须安装到 /usr,/usr/local/ 吗?
    linux命令ps aux|grep xxx详解
    vim 命令,实用
    @Autowired 与@Resource的区别
    srpingmvc 上传图片到服务器
    Git-Windows安装初始
    python判断句子是否匹配某种模式
    50. Pow(x, n)
    49. Group Anagrams
    48. Rotate Image
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13624854.html
Copyright © 2020-2023  润新知