LG P2495 [SDOI2011]消耗战

Description

在一场战争中,战场由 $n$ 个岛屿和 $n-1$ 个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为 $1$ 的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他 $k$ 个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。

侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到 $1$ 号岛屿上)。不过侦查部门还发现了这台机器只能够使用 $m$ 次,所以我们只需要把每次任务完成即可。

Solution

每次的询问只与某些关键点有关,建出这些关键点的虚树

在虚树上DP即可

LG P2495 [SDOI2011]消耗战
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int n,head[250005],head2[250005],tot,tot2,m,dep[250005],fa[250005][19],lg[250005]={-1},cnt,pos[250005],sta[250005],top,dfn[250005];
long long minn[250005];
bool vst[250005];
struct Edge{
    int to,nxt;
    long long w;
}edge[500005],edge2[500005];
inline int read(){
    int w=0,f=1;
    char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
    return w*f;
}
void dfs1(int k,int f){
    dep[k]=dep[f]+1,fa[k][0]=f,dfn[k]=++cnt;
    for(int i=head[k];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v!=f)minn[v]=min(minn[k],edge[i].w),dfs1(v,k);
    }
}
int LCA(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    while(dep[x]>dep[y])x=fa[x][lg[dep[x]-dep[y]]];
    if(x==y)return x;
    for(int i=lg[dep[x]];~i;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
inline void addedge(int x,int y){edge2[++tot2]=(Edge){y,head2[x]},head2[x]=tot2;}
void build(int K){
    sta[top=1]=pos[1],tot2=0;
    for(int i=2;i<=K;i++){
        int lca=LCA(pos[i],sta[top]);
        while(true)
            if(dep[lca]>=dep[sta[top-1]]){
                if(lca!=sta[top]){
                    addedge(lca,sta[top]);
                    if(lca!=sta[top-1])sta[top]=lca;
                    else --top;
                }
                break;
            }
            else addedge(sta[top-1],sta[top]),--top;
        sta[++top]=pos[i];
    }
    while(--top)addedge(sta[top],sta[top+1]);
}
long long dfs2(int k){
    long long ret=minn[k],s=0;
    for(int i=head2[k];i;i=edge2[i].nxt)s+=dfs2(edge2[i].to);
    if(!vst[k])ret=min(ret,s);
    vst[k]=false,head2[k]=0;
    return ret;
}
int main(){
    memset(minn,127,sizeof(minn));
    for(int i=1;i<=250000;i++)lg[i]=lg[i>>1]+1;
    n=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read(),w=read();
        edge[++tot]=(Edge){v,head[u],w},head[u]=tot,edge[++tot]=(Edge){u,head[v],w},head[v]=tot;
    }
    dfs1(1,0);
    for(int i=1;i<=18;i++)for(int k=1;k<=n;k++)fa[k][i]=fa[fa[k][i-1]][i-1];
    m=read();
    for(;m;m--){
        int K=read();
        for(int i=1;i<=K;i++)pos[i]=read(),vst[pos[i]]=true;
        sort(pos+1,pos+K+1,cmp),build(K),printf("%lld\n",dfs2(sta[1]));
    }
    return 0;
}
[SDOI2011]消耗战

 

上一篇:[CF1468A] LaIS - dp,树状数组


下一篇:奖励关题解