bzoj1117[POI2009]救火站Gas 贪心

这道经典题目是贪心算法的应用,通过维护每个节点到根节点的距离来确定覆盖需求。对于每个节点,记录距离为i的节点需要被覆盖的数量和能被覆盖的数量。当需要的覆盖数大于能覆盖的数量时,就需要在该节点放置救火站。大神commonc的解释有助于理解贪心策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是以前的经典题目的难化版本。。
一开始以为要dp,列了很多方程感觉都不合适= =结果发现是贪心QAQ。
我们对于每个点维护两个东西。
以x为根的子树中距离这个点为i的点需要被覆盖多少个
以x为根的子树中距离这个点为i的点还能被覆盖多少个。

转移显然。
那么一种很明显的贪心策略就是能放就放。。如果需要的>能覆盖的明显就需要放一些在这个点上。
问题是怎么抵消两个量呢。
贴commonc大神的解释:

我们知道当我们用一个剩余覆盖范围很广的消防站去覆盖一个离的很近的消防站显然是浪费
所以我们抵消的原则是:再过一步就抵消不了了的时候,我们才去抵消
也就是说,若这个消防站控制范围为i,我们只去抵消距离为ii-1的节点
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;

int fa[N];
typedef long long ll;
int n,S,K;
ll cover[N][21],remain[N][21],ans;
int go[N<<1],tot,next[N<<1],head[N<<1];
inline void add(int x,int y)
{
    go[++tot]=y;
    next[tot]=head[x];
    head[x]=tot;
} 
inline void build(int x)
{
    cover[x][0]=1;
    for(int i=head[x];i;i=next[i])
    {
        int v=go[i];
        if (v==fa[x])continue;
        fa[v]=x;build(v);
        fo(k,0,K-1)cover[x][k+1]+=cover[v][k];
        fd(k,K,1)remain[x][k-1]+=remain[v][k];
    }
    int k=(cover[x][K]+S-1)/S;//多出来的S-1表示任意一个多出来的点都不能丢掉
    ans+=k;
    remain[x][K]+=k*S;
    fo(j,0,K)
    if (remain[x][j])
    {
        for(int k=j;k>=0&&(k>=j-1||x==1);k--)
        {
            if (remain[x][j]<=cover[x][k])
            {
                cover[x][k]-=remain[x][j];
                remain[x][j]=0;
                break;
            }
            remain[x][j]-=cover[x][k];
            cover[x][k]=0;
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&S,&K);
    fo(i,1,n-1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    build(1);
    int tot=0;
    fo(i,0,K)tot+=cover[1][i];
    ans+=(tot+S-1)/S;
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值