[BZOJ2527][POI2011]Meteors(整体二分)

本文介绍了一种利用整体二分法和树状数组解决多个国家流星雨问题的方法。通过调用特定函数,在指定范围内解决所有国家的问题,并详细解释了代码实现细节。

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

题目:

我是超链接

题解:

对于每个国家来说,求出流星雨是第几次是一个妥妥的二分,但是这么多国家的话,我们用整体二分就行了
我们调用solve(1,k,1,n)就可以解决问题,即[1,k]范围内的流星雨可以解决[1,n]的国家
每次让在[l,mid]范围内的流星雨落下,回溯时要删除,二分询问的时候完成任务的国家放在左边,没完成的放在右边
特别要注意流星雨落下时l和r的大小。。
然后就是要开LL

代码:

#include <cstdio>
#include <algorithm>
#define LL long long
using namespace std;
const int N=300005;
struct hh{int hop,id,num;}st[N];
struct lj{int l,r;LL k;}q[N];
int tot,nxt[N],point[N],v[N],m,n;LL c[N],ans[N];
void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}
void add(int loc,LL v){for (int i=loc;i<=m+5;i+=i&(-i)) c[i]+=v;}
LL qurry(int loc)
{
    LL ans=0;
    for (int i=loc;i>=1;i-=i&(-i)) ans+=c[i];
    return ans;
}
int cmp1(hh a,hh b){return a.num<b.num;}
void ef(int l,int r,int a,int b)
{
    if (a>b) return;
    int mid=(l+r)>>1;
    for (int i=l;i<=mid;i++)
    {
        if (q[i].l<=q[i].r) add(q[i].l,q[i].k),add(q[i].r+1,-q[i].k);
        else
        {
            add(q[i].l,q[i].k);add(m+1,-q[i].k);
            add(1,q[i].k); add(q[i].r+1,-q[i].k);
        }
    }
    if (l==r)
    {
        for (int x=a;x<=b;x++)
        {
        LL t=0;
        for (int i=point[st[x].id];i;i=nxt[i])
        {
            t+=qurry(v[i]);
            if (t>=st[x].hop) {ans[st[x].id]=l;break;}
        }
        if (t<st[x].hop) ans[st[x].id]=-1;
        }

        for (int i=l;i<=mid;i++)
        {
        if (q[i].l<=q[i].r) add(q[i].l,-q[i].k),add(q[i].r+1,q[i].k);
        else
        {
            add(q[i].l,-q[i].k);add(m+1,q[i].k);
            add(1,-q[i].k); add(q[i].r+1,q[i].k);
        }
        }
        return;
    }

    int pa=0,pb=b-a+1;
    for (int x=a;x<=b;x++)
    {
        LL t=0;
        for (int i=point[st[x].id];i;i=nxt[i])
        {
            t+=qurry(v[i]);
            if (t>=st[x].hop) {st[x].num=++pa;break;}
        }
        if (t<st[x].hop) st[x].num=++pb,st[x].hop-=t;
    }
    for (int i=l;i<=mid;i++)
    {
        if (q[i].l<=q[i].r) add(q[i].l,-q[i].k),add(q[i].r+1,q[i].k);
        else
        {
            add(q[i].l,-q[i].k);add(m+1,q[i].k);
            add(1,-q[i].k); add(q[i].r+1,q[i].k);
        }
    }
    sort(st+a,st+b+1,cmp1);
    ef(l,mid,a,a+pa-1);
    ef(mid+1,r,a+pa,b);
}
int cmp(hh a,hh b){return a.id<b.id;}
int main()
{
    scanf("%d%d",&n,&m);int x,k;
    for (int i=1;i<=m;i++) scanf("%d",&x),addline(x,i);
    for (int i=1;i<=n;i++) scanf("%lld",&st[i].hop),st[i].id=i;
    scanf("%d",&k);
    for (int i=1;i<=k;i++) scanf("%d%d%lld",&q[i].l,&q[i].r,&q[i].k);
    ef(1,k,1,n);
    sort(st+1,st+n+1,cmp);
    for (int i=1;i<=n;i++) 
      if (ans[i]==-1) printf("NIE\n");else printf("%lld\n",ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值