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)

那么有了多组询问我们就在虚树上搞这个,需要注意的是虚树上的一条父子边就对应着原树上一条父子链,而权值就是那个父子链的最小值。可以用倍增一起维护掉。

需要注意的是...要用long long啊

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
int inf=1000000000;
ll inf_ll=10000000000000000LL;
#define gc getchar()
int g_i()
{
    int tmp=0; bool fu=0; char s;
    while(s=gc,s!=‘-‘&&(s<‘0‘||s>‘9‘)) ;
    if(s==‘-‘) fu=1; else tmp=s-‘0‘;
    while(s=gc,s>=‘0‘&&s<=‘9‘) tmp=tmp*10+s-‘0‘;
    if(fu) return -tmp; else return tmp;
}
#define gi g_i()
#define pob
#define pc(x) putchar(x)
namespace ib {char b[100];}
inline void pll(ll x)
{
    if(x==0) {pc(48); return;}
    if(x<0) {pc(‘-‘); x=-x;}
    char *s=ib::b;
    while(x) *(++s)=x%10, x/=10;
    while(s!=ib::b) pc((*(s--))+48);
}
#define SZ 1234567
#define D 20
#define _els ;else
//real tree
namespace rt
{
int n,fst[SZ],nxt[SZ],vb[SZ],vc[SZ],fa[SZ],dep[SZ],M=0,dfsn[SZ],C=0,sz[SZ],fe[SZ];
int up[SZ][D],mine[SZ][D];
void ad_de(int a,int b,int c) {++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b; vc[M]=c;}
void adde(int a,int b,int c) {ad_de(a,b,c); ad_de(b,a,c);}
void dfs(int p)
{
    dfsn[p]=++C; sz[p]=1;
    for(int e=fst[p];e;e=nxt[e])
    {
        int b=vb[e]; if(b==fa[p]) continue;
        fa[b]=up[b][0]=p; fe[b]=vc[e]; mine[b][0]=fe[b];
        dep[b]=dep[p]+1; dfs(b); sz[p]+=sz[b];
    }
}
void build()
{
    dfs(1);
    for(int g=1;g<D;g++)
    {
        for(int i=1;i<=n;i++) mine[i][g]=inf;
    }
    for(int g=1;g<D;g++)
    {
        for(int i=1;i<=n;i++)
        {
            if(!up[i][g-1]) continue;
            up[i][g]=up[up[i][g-1]][g-1];
            mine[i][g]=min(mine[i][g-1],mine[up[i][g-1]][g-1]);
        }
    }
}
//jump up (x=fa[x]) until dep[x]=d
int jmp(int x,int d)
{
    for(int i=D-1;i>=0;i--)
    {
        if(!up[x][i]||dep[up[x][i]]<d)_els x=up[x][i];
    }
    return x;
}
int gmin(int x,int d)
{
    int minn=inf;
    for(int i=D-1;i>=0;i--)
    {
        if(!up[x][i]||dep[up[x][i]]<d)_els minn=min(minn,mine[x][i]), x=up[x][i];
    }
    return minn;
}
int lca(int x,int y)
{
    if(dep[x]>dep[y]) swap(x,y);
    y=jmp(y,dep[x]);
    if(x==y) return x;
    for(int i=D-1;i>=0;i--)
    {
        if(up[x][i]!=up[y][i]) x=up[x][i], y=up[y][i];
    }
    return fa[x];
}
}
//virtual tree
namespace vt
{
#define f_ first
#define s_ second
typedef pair<int,int> pii;
//vs: points in vtree
int sn,ss[SZ],vn,vs[SZ],stn=0,st[SZ],vfa[SZ],fc[SZ],nc[SZ];
ll f[SZ],vfe[SZ];
bool saf[SZ];
bool cmp_dfsn(int a,int b) {return rt::dfsn[a]<rt::dfsn[b];}
ll dp(int x)
{
    if(!saf[x]) return f[x]=vfe[x];
    ll sum=0;
    for(int c=fc[x];c;c=nc[c]) sum+=dp(c);
    return f[x]=min((ll)vfe[x],sum);
}
void build()
{
    vn=stn=0;
    ss[++sn]=1;
    sort(ss+1,ss+1+sn,cmp_dfsn);
    for(int i=1;i<=sn;i++) vs[++vn]=ss[i], saf[ss[i]]=i==1;
    for(int i=1;i<=sn;i++)
    {
        int x=ss[i];
        if(!stn) {st[++stn]=x; vfa[x]=0; continue;}
        int lca=rt::lca(x,st[stn]);
        for(;rt::dep[st[stn]]>rt::dep[lca];--stn)
        {
            if(rt::dep[st[stn-1]]<=rt::dep[lca]) vfa[st[stn]]=lca;
        }
        if(st[stn]!=lca)
        {
            vs[++vn]=lca;
            saf[lca]=1;
            vfa[lca]=st[stn];
            st[++stn]=lca;
        }
        vfa[x]=lca; st[++stn]=x;
    }
    sort(vs+1,vs+1+vn,cmp_dfsn);
    for(int i=1;i<=vn;i++) fc[vs[i]]=0;
    for(int i=1;i<=vn;i++)
    {
        int x=vs[i]; f[x]=inf_ll;
        if(i>1) vfe[x]=rt::gmin(x,rt::dep[vfa[x]]);
        else vfe[x]=inf_ll;
        int f=vfa[x];
        nc[x]=fc[f]; fc[f]=x;
    }
    pll(dp(1)); pc(10);
}
}
int main()
{
    rt::n=gi;
    for(int i=1;i<rt::n;i++)
    {
        int x=gi,y=gi,z=gi;
        rt::adde(x,y,z);
    }
    rt::build();
    int q=gi;
    while(q--)
    {
        vt::sn=gi;
        for(int i=1;i<=vt::sn;i++) vt::ss[i]=gi;
        vt::build();
    }
}
时间: 2024-12-25 20:30:03

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】[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】 消耗战

http://www.lydsy.com/JudgeOnline/problem.php?id=2286 (题目链接) 一个小小的细节,WA了一天,欲哭无泪了.. 题意:给出一个n个节点的带权树,总共m次询问,每次询问给出K个节点标号,求出切断这些节点与1号节点的路径的最少花费. solution  构造虚数+树形dp.  首先,有关虚树的题有一个特征,就是题目会给出sigema(k[i])的范围,保证不会太大.所以我们考虑对于每一次询问构造一棵虚树,然后再在虚树上跑dp,可以大大减少复杂度,比

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就很不值得 于是我们就要取出那