[bzoj2286]消耗战

[bzoj2286]消耗战


建虚树dp

  • 代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
typedef long long ll;
int anc[N][22];
ll mn[N];
const ll INF=1000000000000000000;
int n,m;
int num,dfn[N],dep[N];
int point[N];
bool cmp(const int a,const int b) {
    return dfn[a]<dfn[b];
}
namespace Tr_all {
int hed[N],to[N];
ll val[N];
int cnt,nxt[N];
inline void adde(int u,int v,ll w) {
    ++cnt;
    val[cnt]=w,to[cnt]=v,nxt[cnt]=hed[u];
    hed[u]=cnt;
}
inline void dfs(int x,int pre) {
    dfn[x]=++num;
    dep[x]=dep[pre]+1;
    if(x==1)mn[x]=INF;
    anc[x][0]=pre;
    for(int i=1; 1<<i<=n; i++) {
        anc[x][i]=anc[anc[x][i-1]][i-1];
    }
    for(int i=hed[x]; i; i=nxt[i]) {
        int v=to[i];
        if(v==pre)continue;
        mn[v]=min(mn[x],(ll)val[i]);
        dfs(v,x);
    }
}
int LCA(int x,int y) {
    if(dep[x]<dep[y])swap(x,y);
    for(int i=19; ~i; i--)if(dep[anc[x][i]]>=dep[y])
            x=anc[x][i];
    if(x==y)return x;
    for(int i=19; ~i; i--)if(anc[x][i]!=anc[y][i])
            x=anc[x][i],y=anc[y][i];
    return anc[x][0];
}
}
using Tr_all::LCA;
namespace Tr_cur {
int hed[N],to[N],nxt[N],cnt;
inline void adde(int u,int v) {
//		cout<<u<<"-->"<<v<<endl;
    ++cnt;
    to[cnt]=v,nxt[cnt]=hed[u];
    hed[u]=cnt;
}
inline void clear() {
    cnt=0;
}
inline ll DP(int x) {
    ll val=0;
    if(hed[x]==0)return mn[x];
    for(int i=hed[x]; i; i=nxt[i]) {
        int v=to[i];
        val+=DP(v);
    }
    hed[x]=0;
    return min(val,mn[x]);
}
}
using Tr_cur::DP;
int stk[N],top;

int main()
{
    scanf("%d",&n);
    for(int i=1; i<n; i++) {
        int u,v;
        ll w;
        scanf("%d%d%lld",&u,&v,&w);
        Tr_all::adde(u,v,w);
        Tr_all::adde(v,u,w);
    }
    Tr_all::dfs(1,0);
    scanf("%d",&m);
    while(m--) {
        int tot;
        scanf("%d",&tot);
        for(int i=1; i<=tot; i++)
            scanf("%d",&point[i]);
        sort(point+1,point+tot+1,cmp);
        stk[(top=1)]=1;
        /*insert*/
        for(int i=1; i<=tot; i++) {
            int u=point[i];
            int lca=LCA(u,stk[top]);
            if(top==1) {
                stk[++top]=u;
                continue;
            }
            if(lca==stk[top])continue;
            while(top>1&&dep[stk[top-1]]>dep[lca]) {
                Tr_cur::adde(stk[top-1],stk[top]);
                --top;
            }
            if(dep[stk[top]]>dep[lca]) {
                Tr_cur::adde(lca,stk[top]);
                top--;
            }
            if(dep[stk[top]]<dep[lca]) stk[++top]=lca;
            stk[++top]=u;
        }
        while(--top) Tr_cur::adde(stk[top],stk[top+1]);
        /**/
        printf("%lld\n",DP(1));
        Tr_cur::clear();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值