【bzoj2286】 消耗战

http://www.lydsy.com/JudgeOnline/problem.php?id=2286 (题目链接)

一个小小的细节,WA了一天,欲哭无泪了。。

题意:给出一个n个节点的带权树,总共m次询问,每次询问给出K个节点标号,求出切断这些节点与1号节点的路径的最少花费。

solution 
  构造虚数+树形dp。 
  首先,有关虚树的题有一个特征,就是题目会给出sigema(k[i])的范围,保证不会太大。所以我们考虑对于每一次询问构造一棵虚树,然后再在虚树上跑dp,可以大大减少复杂度,比如u,v两点之间没有其他询问点,那么我们就可以把uv直接连起来,中间的点是什么我们并不关心。我们只要建出这样一棵树即可:只含当前询问点和它们的lca,并且相对位置关系不变。 
举个例子,比如说选1,5,8,10号节点。 
 
那么构造出来的的虚树就是: 
 
  那么如何构造虚树呢? 
  我们先对原树dfs一遍,预处理出dfs序(mark[]),将询问点按照dfs序排序,依次插入一个栈,来动态维护一个叫做“最右链”的东西,就是最右边的一条链……这个也不太好说明,最好自己看着代码模拟一遍…… 
  用虚树还要满足一个条件,就是要维护的信息。例如,和,最大,最小,都有类似于前缀和的性质。就是我们可以从v(u的后代)直接求出u的答案,而不需要遍历u到v的所有边,否则虚树就没有降低复杂度,因为每次还是要在原树上走。在这道题中,我们用一个数组mn[i]来维护节点i到根节点1的路径上的花费最小的那一条边权,mn[i]我们可以在dfs时预处理出。这有什么用呢,看下面。 
  关于如何在虚树上dp,我么有了mn[]数组后,就变的很简单,f[i]表示断开询问点i以及i的子树上的询问点到根节点1的路径的最小花费。转移方程:f[i]=min(mn[i],sigema(f[e[i].to]),其中e[i].to指的是i节点的孩子节点。 
  可是我们考虑一种情况,借用上面的图1,若询问点是2和8,mn[8]=4->8=1,mn[2]=1->2=4,按照我们的算法,那么得出的答案就会是1,而这样是不正确的。 
  也就是说,当存在询问点u,v设deep[u]<deep[v]使lca(u,v)==u时,我们的dp方程是不成立的。对于这种情况,选择切断深度浅的点的mn[u]是最优的。想一想,若切断了mn[u],那么在i的子树上的询问点v自然也被切断了。 
  所以我们在构建虚树的时候,就预先将这种情况处理掉,也就是在u,v中只选择u放入虚树中。 
  最后温馨提示:最后输出的答案可能会很大,记得开LL。inf要开到很大,2147483647是远远不够的(博主就这样WA了一天= =)。还有邻接表头head[]不能直接memset,O(mn)的复杂度是承受不了的。

代码:

// bzoj2286
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define MOD 1000000007
#define inf 1e60 //important
#define LL long long
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline int getint() {
    int x=0,f=1;char ch=getchar();
    while (ch>‘9‘ || ch<‘0‘) {if (ch==‘-‘) f=-1;ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}

const int maxn=250010;
struct edge {int to,next,w;}e[maxn<<2];
int a[maxn],head[maxn],mark[maxn],deep[maxn],fa[maxn][20],bin[20],s[maxn];
LL f[maxn],mn[maxn];
int n,m,cnt,dfn;

void insert(int u,int v,int w) {
    if (w>0) {
        e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w;
        e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].w=w;
    }
    else {
        if (u==v) return;
        e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
    }
}
void dfs(int u) {
    mark[u]=++dfn;
    for (int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
    for (int i=head[u];i;i=e[i].next) if (e[i].to!=fa[u][0]) {
            mn[e[i].to]=min(mn[u],(LL)e[i].w);
            fa[e[i].to][0]=u;
            deep[e[i].to]=deep[u]+1;
            dfs(e[i].to);
        }
}
bool cmp(int x,int y) {
    return mark[x]<mark[y];
}
int lca(int x,int y) {
    if (deep[x]<deep[y]) swap(x,y);
    int t=deep[x]-deep[y];
    for (int i=0;bin[i]<=t;i++) if (t&bin[i]) x=fa[x][i];
    for (int i=19;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return x==y?x:fa[x][0];
}
void build(int K) {
    int tot=0,top=0;
    cnt=0;
    a[++tot]=a[1];
    for (int i=2;i<=K;i++) if (lca(a[tot],a[i])!=a[tot]) a[++tot]=a[i];
    s[++top]=1;
    for (int i=1;i<=tot;i++) {
        int t=a[i],x=0;
        while (top) {
            x=lca(a[i],s[top]);
            if (top>1 && deep[x]<deep[s[top-1]]) insert(s[top-1],s[top],0),top--;
            else if (deep[x]<deep[s[top]]) {insert(x,s[top--],0);break;}
            else break;
        }
        if (s[top]!=x) s[++top]=x;
        s[++top]=t;
    }
    while (--top) insert(s[top],s[top+1],0);
}
void dp(int u) {
    LL tmp=0;
    f[u]=mn[u];
    for (int i=head[u];i;i=e[i].next) {
        dp(e[i].to);
        tmp+=f[e[i].to];
    }
    head[u]=0;
    f[u]=tmp==0?mn[u]:min(tmp,mn[u]);
}
int main() {
    bin[0]=1;for (int i=1;i<20;i++) bin[i]=bin[i-1]<<1;
    n=getint();
    for (int i=1;i<n;i++) {
        int u=getint(),v=getint(),w=getint();
        insert(u,v,w);
    }
    mn[1]=inf;dfs(1);
    m=getint();
    memset(head,0,sizeof(head));
    while (m--) {
        int K=getint();
        for (int i=1;i<=K;i++) a[i]=getint();
        sort(a+1,a+1+K,cmp);
        build(K);
        dp(1);
        printf("%lld\n",f[1]);
    }
    return 0;
}

  

时间: 2024-10-09 23:01:56

【bzoj2286】 消耗战的相关文章

[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 消耗战【虚树+倍增lca+单调栈】

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

bzoj2286 消耗战

还是虚树的题目啊... 如果只有一个询问,我们这么考虑,可以设dp[x]为只删除x子树内和x到父亲的边,使得x这棵子树内的能源岛屿都与x的父亲不连通的最小花费. 这样如果x本身是能源岛屿,那么dp[x]=fe[x],否则dp[x]=min(fe[x],sum{dp[son[x]]})类似这样.(fe表示父亲边,fe[1]=inf) 那么有了多组询问我们就在虚树上搞这个,需要注意的是虚树上的一条父子边就对应着原树上一条父子链,而权值就是那个父子链的最小值.可以用倍增一起维护掉. 需要注意的是...

【BZOJ2286】[Sdoi2011]消耗战 虚树

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

【BZOJ2286】消耗战(虚树,DFS序,树形DP)

题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. 对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1 思路:第一题虚树,需要详细地记录一下. 对于此题,朴素的树形DP很好理解: dp[u]为将u子树中的关键点全部切断的最小代价 dp[u]=min(cut[u]

【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消耗战

Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3003  Solved: 1081 Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿.由于不同桥梁的材质和结构不同,所以炸毁不

BZOJ2286 [Sdoi2011]消耗战

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

[bzoj2286][Sdoi2011]消耗战(虚树上的DP)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2286 分析:对于普通的树形dp:f[x]=min(∑f[son],m[x]),其中f[x]表示以x为根的子树所有关键点全部断开所需要的最少代价,m[x]表示从根节点到x节点的路径上最短的边 这样的话复杂度是n*m的,明显TLE 注意到数据范围里提到,所有询问的总的点数<=n,也就是说询问虽然很多,但每次询问的点的个数不多,也就是说如果对所有的点做树形dp就很不值得 于是我们就要取出那