【Bzoj2286】消耗战(虚树+DP)

Description

题目链接

Solution

在虚树上跑DP即可

Code

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define ll long long
#define N 250010
using namespace std;

const ll Inf=1ll<<60;
struct info{int to,nex;ll w;}vir[N*2],e[N*2];
int n,m,tot,head[N],dfn[N],cnt;
int _log,f[N][20],dep[N];
int q[N],sta[N],top;
ll dis[N],dp[N];

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline void Link(int u,int v,int w){
    e[++tot].to=v;e[tot].w=w;e[tot].nex=head[u];head[u]=tot;
}

inline void Link_vir(int u,int v){
    if(u==v) return;
    vir[++tot].to=v;vir[tot].nex=head[u];head[u]=tot;
}

void dfs(int u, int fa){
    dfn[u]=++cnt;
    for (int j=1;j<=_log;++j) f[u][j]=f[f[u][j-1]][j-1];

    for(int i=head[u];i;i=e[i].nex) {
        int v=e[i].to;
        if (v==fa) continue;
        f[v][0]=u;
        dis[v]=min(dis[u],e[i].w);
        dep[v]=dep[u]+1;
        dfs(v,u);
    }
}

int LCA(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    int d=dep[v]-dep[u];

    for(int i=0;i<=_log;++i)
        if(d&(1<<i)) v=f[v][i];
    if(u==v) return v;

    for(int i=_log;i>=0;--i)
        if(f[u][i]!=f[v][i]){
            u=f[u][i];
            v=f[v][i];
        }
    return f[u][0];
}

void DP(int x){
    ll tmp=0;dp[x]=dis[x];
    for(int i=head[x];i;i=vir[i].nex){
        int v=vir[i].to;
        DP(v);
        tmp+=dp[v];
    }
    head[x]=0;
    if(!tmp) dp[x]=dis[x];
    else if(tmp<dp[x]) dp[x]=tmp;
}

bool cmp(int a,int b){return dfn[a]<dfn[b];}
void solve(){
    m=read();tot=0;
    for(int i=1;i<=m;++i) q[i]=read();
    sort(q+1,q+m+1,cmp);
    cnt=1;
    for(int i=2;i<=m;++i) if(LCA(q[i],q[cnt])!=q[cnt]) q[++cnt]=q[i];
    sta[top=1]=1;
    for(int i=1;i<=cnt;++i){
        int grand=LCA(q[i],sta[top]);
        while(1){
            if(dep[sta[top-1]]<=dep[grand]){
                Link_vir(grand,sta[top]); top--;
                if(sta[top]!=grand) sta[++top]=grand;
                break;
            }
            Link_vir(sta[top-1],sta[top]); top--;
        }
        if(sta[top]!=q[i]) sta[++top]=q[i];
    }
    top--;
    while(top) Link_vir(sta[top],sta[top+1]),top--;
    DP(1);
    printf("%lld\n",dp[1]);
}

int main(){
    n=read();_log=log(n)/log(2);
    for(int i=1;i<n;++i){
        int u=read(),v=read(),w=read();
        Link(u,v,w);
        Link(v,u,w);
    }
    dis[1]=Inf;dfs(1,0);
    memset(head,0,sizeof(head));
    int k=read();while(k--) solve();
    return 0;
}

原文地址:https://www.cnblogs.com/void-f/p/8678080.html

时间: 2024-10-10 01:53:59

【Bzoj2286】消耗战(虚树+DP)的相关文章

[SDOI2011][BZOJ2286] 消耗战|虚树|树型dp|树上倍增LCA

2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1040  Solved: 363[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸

【BZOJ-2286】消耗战 虚树 + 树形DP

2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2120  Solved: 752[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁

【BZOJ2286】[Sdoi2011]消耗战 虚树

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

BZOJ 2286 消耗战 (虚树+树形DP)

给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<=500000) 考虑树形DP,我们令mn[i]表示i节点无法与1节点相连切除的最小权值.显然有mn[i]=min(E(fa,i),mn[fa]).大致就是i到1的简单路径上的最小边.我们对于每个询问.把询问的点不妨称为关键点.令dp[i]表示i节点不能与子树的关键点连接切掉的最小权值.那么有,如果son[i]

bzoj 3572 [Hnoi2014]世界树(虚树+DP)

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.     世界树的形态可以用一个数学模型来描述:世界树中有n个

BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$(f,x)$,讨论一下边上的点的子树应该靠谁更近 倍增求出分界点 注意有些没出现在虚树上的子树 注意讨论的时候只讨论链上的不包括端点,否则$f$的子树会被贡献多次 学到的一些$trick:$ 1.$pair$的妙用 2.不需要建出虚树只要求虚树的$dfs$序(拓扑序)和$fa$就可以$DP$了 注意

CodeForces - 613D:Kingdom and its Cities(虚树+DP)

Meanwhile, the kingdom of K is getting ready for the marriage of the King's daughter. However, in order not to lose face in front of the relatives, the King should first finish reforms in his kingdom. As the King can not wait for his daughter's marri

P2495 [SDOI2011]消耗战 虚树

这是我做的第一道虚树题啊,赶脚不错.其实虚树也没什么奇怪的,就是每棵树给你一些点,让你多次查询,但是我不想每次都O(n),所以我们每次针对给的点建一棵虚树,只包含这些点和lca,然后在这棵虚树上进行树形dp,维护每个点的最小连边权值,这样的复杂度就会降低不少.这里我写了两种写法(其实都是抄的),一种是正常建树的正常做法,还有一种是不用建树,只用堆维护,模拟一棵树的操作,维护欧拉序,就是一个点有进入的编号,也有出去的编号.这样就可以不用真正建出虚树而能进行查询. 题干: 题目描述 在一场战争中,战

Codeforces 1111E Tree 虚树 + dp

直接把 r 加进去建虚树, 考虑虚树上的dp, 我们考虑虚树的dfs序的顺序dp过去. dp[ i ][ j ]  表示到 i 这个点为止, 分成 j 组有多少种合法方案. dp[ i ][ j ] = dp[ i - 1 ][ j ] * (j - have[ i ])  + dp[ i - 1 ][ j - 1 ], have[ i ] 表示 i 的祖先中有多少个在a中出现. #include<bits/stdc++.h> using namespace std; const int N

HDU-6035:Colorful Tree(虚树+DP)

这里有三道长得像的题: 一:HDU6036: There is a tree with nn nodes, each of which has a type of color represented by an integer, where the color of node ii is cici. The path between each two different nodes is unique, of which we define the value as the number of