zoukankan      html  css  js  c++  java
  • BZOJ2286 [Sdoi2011]消耗战

    题目描述

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

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

    输入输出格式

    输入格式:

    第一行一个整数n,代表岛屿数量。

    接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。

    第n+1行,一个整数m,代表敌方机器能使用的次数。

    接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。

    输出格式:

    输出有m行,分别代表每次任务的最小代价。

    输入输出样例

    输入样例#1:
    10
    1 5 13
    1 9 6
    2 1 19
    2 4 8
    2 3 91
    5 6 8
    7 5 4
    7 8 31
    10 7 9
    3
    2 10 6
    4 5 7 8 3
    3 9 4 6
    
    输出样例#1:
    12
    32
    22
    

    说明

    【数据规模和约定】

    对于10%的数据,2<=n<=10,1<=m<=5,1<=ki<=n-1

    对于20%的数据,2<=n<=100,1<=m<=100,1<=ki<=min(10,n-1)

    对于40%的数据,2<=n<=1000,m>=1,sigma(ki)<=500000,1<=ki<=min(15,n-1)

    对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

    题解:

      这个题目,首先我们考虑暴力dp,设dp[i]表示保证子树内部都合法的最小花费,那么显然,dp[i]=sum(dp[to]),dp[i]=min(dp[i],val[i]),val[i]表示i到根节点路径上的最小边权。然而看看数据范围……

      想怎么优化,显然每次询问的正真用到的关键点其实是很少的,所以我们可以打一下虚树,这样就可以把询问复杂度降为m*k*logk。于是就套一下虚树模板就可以了(然而我是现学的)。

    代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #define MAXN 400100
    #define ll long long
    using namespace std;
    ll f[MAXN],val[MAXN];
    int top[MAXN],size[MAXN],dep[MAXN],son[MAXN],dfn[MAXN],fa[MAXN],b[MAXN];
    int s[MAXN*2],q[MAXN];
    struct edge{
        int first;
        int next;
        int to;
        int quan;
    }a[MAXN*2],a2[MAXN*2];
    int n,m,num=0,num2=0;
    
    void addedge(int from,int to,int quan){
        a[++num].to=to;
        a[num].quan=quan;
        a[num].next=a[from].first;
        a[from].first=num;
    }
    
    void dfs1(int now,int F){
        fa[now]=F,size[now]=1,dep[now]=dep[F]+1;
        for(int i=a[now].first;i;i=a[i].next){
            int to=a[i].to,quan=a[i].quan;if(to==F) continue;
            val[to]=min((ll)quan,val[now]);
            dfs1(to,now);
            size[now]+=size[to];
            if(size[to]>size[son[now]]) son[now]=to;
        }
    }
    
    void dfs2(int now,int tp){
        top[now]=tp;dfn[now]=++num2;
        if(son[now]) dfs2(son[now],tp);
        for(int i=a[now].first;i;i=a[i].next){
            int to=a[i].to;
            if(to==fa[now]||to==son[now]) continue;
            dfs2(to,to);
        }
    }
    
    int Lca(int x,int y){
        int topx=top[x],topy=top[y];
        while(topx!=topy){
            if(dep[topx]<dep[topy]) swap(topx,topy),swap(x,y);
            x=fa[topx];
            topx=top[x];
        }
        if(dep[x]<dep[y]) return x;
        return y;
    }
    
    bool cmp(int x,int y){
        return dfn[x]<dfn[y];
    }
    
    void addedge2(int from,int to,int quan){
        a2[++num].to=to;
        a2[num].quan=quan;
        a2[num].next=a2[from].first;
        a2[from].first=num;
    }
    
    void DP(int now,int FA){
        if(b[now]) f[now]=val[now];
        else f[now]=0;
        for(int i=a2[now].first;i;i=a2[i].next){
            int to=a2[i].to;
            if(to==FA||to==now) continue;
            DP(to,now);
            f[now]+=f[to];
        }
        f[now]=min(f[now],val[now]);
        b[now]=a2[now].first=0;
    }
    
    void work(){
        int tot,tp=0;
        scanf("%d",&tot);
        for(int i=1;i<=tot;i++) scanf("%d",&q[i]),b[q[i]]=1;
        sort(q+1,q+tot+1,cmp);
        num=0;
        s[++tp]=1;
        for(int i=1;i<=tot;i++){
            int lca=Lca(q[i],s[tp]);
            while(1){
                if(dep[s[tp-1]]<=dep[lca]){
                    addedge2(s[tp],lca,0),addedge2(lca,s[tp],0);tp--;
                    if(s[tp]!=lca) s[++tp]=lca;
                    break;
                }
                addedge2(s[tp],s[tp-1],0),addedge2(s[tp-1],s[tp],0);tp--;
            }
            s[++tp]=q[i];
        }
        while(tp>1) {addedge2(s[tp],s[tp-1],0),addedge2(s[tp-1],s[tp],0);tp--;}
        DP(1,0);
        printf("%lld
    ",f[1]);
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n-1;i++){
            int x,y,z;scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z),addedge(y,x,z);
        }
        val[1]=1ll<<60;
        dfs1(1,0);dfs2(1,1);
        scanf("%d",&m);
        while(m--) work();
        return 0;
    }
  • 相关阅读:
    中债登、银行间市场、上清所… 这些机构你能分清几个?
    期货界的四大天王
    心理学的几个现象
    西方金融交易员揭露行业潜规则
    瑞银保住欧股交易经纪龙头宝座 算法交易傲视同业
    【Python】 zabbixAPI的包装pyzabbix
    【Python】 日志管理logging
    【Python】 子进程创建与使用subprocess
    【Python】 配置解析ConfigParser & 命令行参数解析optparser
    【Python】 SSH连接的paramiko
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7616344.html
Copyright © 2011-2022 走看看