P2495 [SDOI2011]消耗战 (虚树)

Posted ctyakwf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2495 [SDOI2011]消耗战 (虚树)相关的知识,希望对你有一定的参考价值。

虚树对于多次询问的时候有这优化复杂度的好处,其原理就是只保留有用节点和必须保留的有用节点的lca

先求一遍dfs序后,用栈模拟操作,根据lca是否在栈中确定是否要将lca加入栈,因为重构了树,因此原来的边的信息需要进行更换

对于本题,新的边其实就是路径上的边权的最小值,这是因为随便切掉一个边就能把他们断开。

技术图片
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
const int mod=998244353;
struct node{
    int x;
    ll w;
};
vector<node> g[N],g1[N];
int n;
int dfn[N],times;
int f[N][25],depth[N];
ll cost[N][25];
int st[N];
int cnt[N];
int q[N];
ll dp[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]=min(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 x,int y){
    return dfn[x]<dfn[y];
}
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=1e18;
    if(depth[a]>depth[b])
        swap(a,b);
    for(int i=21;i>=0;i--){
        if(depth[f[b][i]]>=depth[a]){
            ans=min(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 i;
    for(i=0;i<g[u].size();i++){
        int v=g[u][i].x;
        get(v);
        if(st[v])
            dp[u]+=g[u][i].w;
        else
            dp[u]+=min(g[u][i].w,dp[v]);
        st[v]=0;dp[v]=0;
    }
    g[u].clear();
}
int main(){
    ios::sync_with_stdio(false);
    int i;
    cin>>n;
    for(i=1;i<n;i++){
        int a,b,c;
        cin>>a>>b>>c;
        g1[a].push_back({b,c});
        g1[b].push_back({a,c});
    }
    //cout<<"aa"<<endl;
    dfs(1,0,0);
    int m;
    cin>>m;
    while(m--){
        int k;
        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]);
        }
        get(1);
        cout<<dp[1]<<endl;
        dp[1]=0;
    }
    return 0;
}
View Code

 

以上是关于P2495 [SDOI2011]消耗战 (虚树)的主要内容,如果未能解决你的问题,请参考以下文章

luogu P2495 [SDOI2011]消耗战

P2495 [SDOI2011]消耗战

AC日记——[SDOI2011]消耗战 洛谷 P2495

●洛谷P2495 [SDOI2011]消耗战

Luogu P2495 [SDOI2011]消耗战

题解SDOI2011消耗战