2527:[Poi2011]Meteors(整体二分)

2527:[Poi2011]Meteors

时间限制: 2000 ms 内存限制: 131072 KB

题目描述

Byteotian Interstellar Union有 N N 个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为M份(第 M M 份和第1份相邻),第i份上有第 Ai A i 个国家的太空站。

这个星球经常会下陨石雨。BIU已经预测了接下来 K K 场陨石雨的情况。

BIU的第i个成员国希望能够收集 Pi P i 单位的陨石样本。你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。

输入:

第一行是两个数 N,M N , M
第二行有 M M 个数,第i个数 Oi O i 表示第i段轨道上有第 Oi O i 个国家的太空站。
第三行有 N N 个数,第i个数 Pi P i 表示第 i i 个国家希望收集的陨石数量。
第四行有一个数K,表示BIU预测了接下来的 K K 场陨石雨。

接下来K行,每行有三个数 Li,Ri,Ai L i , R i , A i ,表示第 K K 场陨石雨的发生地点在从Li顺时针到 Ri R i 的区间中(如果 LiRi L i ≤ R i ,就是 Li L i , Li+1 L i + 1 ,…, Ri R i ,否则就是 Ri R i , Ri+1 R i + 1 ,…, m1 m − 1 , m m ,1,…,Li),向区间中的每个太空站提供 Ai A i 单位的陨石样本。

输出:

N N 行。第i行的数 Wi W i 表示第 i i 个国家在第Wi波陨石雨之后能够收集到足够的陨石样本。如果到第 K K 波结束后仍然收集不到,输出NIE。

数据范围:

1n,m,k3105
1Pi109 1 ≤ P i ≤ 10 9
1Ai<109 1 ≤ A i < 10 9

输入样例
3 5
1 3 2 1 3
10 5 7
3
4 2 4
1 3 1
3 5 2
输出样例
3
NIE
1

   
   
   
   
   
   
   
   
   
   
   
   

解:

首先想到用链表存一下每个国家收集点的位置,然后就还是按照时间二分,主要判一下无解的情况。而且比较坑的是,如果一个国家收集点很多,收集的陨石可能会爆 longlong l o n g l o n g ,要及时break。
code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define lowbit(x) ((x)&(-x))
using namespace std;
struct data{
    int l,r;
    long long a;
}q[300005];
struct lxy1{
    int id,next;
}eg[3000005];

queue <int> d1,d2;
int n,m,k,cnt,root;
int cty[300005],ans[300005],head[300005];
long long aim[300005];
long long b[300005];

int readit()
{
    int a=0;char s;
    s=getchar();
    while(s<'0'||s>'9') s=getchar();
    while(s>='0'&&s<='9')
    {
        a=a*10+s-'0';
        s=getchar();
    }
    return a;
}

void add(int op,int ed)
{
    eg[++cnt].next=head[op];
    eg[cnt].id=ed;
    head[op]=cnt;
}

void modify(int u,long long x)
{
    while(u<=m){
        b[u]+=x;
        u+=lowbit(u);
    }
}

long long query(int u)
{
    long long ret=0;
    while(u>0){
        ret+=b[u];
        u-=lowbit(u);
    }
    return ret;
}

void cdq(int ml,int mr,int ql,int qr)
{
    int midm=(ml+mr)>>1;
    if(ml==mr&&ml!=k)
    {
        for(int i=ql;i<=qr;i++)
          ans[cty[i]]=ml;
        return;
    }
    for(int i=ml;i<=midm;i++)
    {
        if(q[i].l<=q[i].r) modify(q[i].l,q[i].a),modify(q[i].r+1,-q[i].a);
        else modify(q[i].l,q[i].a),modify(1,q[i].a),modify(q[i].r+1,-q[i].a);
    }
    int gg=ql-1,mid;
    for(int i=ql;i<=qr;i++)
    {
        long long s=0;
        for(int j=head[cty[i]];j!=-1;j=eg[j].next){
          s+=query(eg[j].id);
          if(s>=aim[cty[i]]) break;
        }
        if(s<aim[cty[i]]&&ml==k){
            ans[cty[i]]=-1;
        }
        else if(s>=aim[cty[i]]) d1.push(cty[i]);
        else if(s<aim[cty[i]]) d2.push(cty[i]),aim[cty[i]]-=s;
    }
    if(ml==k) {
      while(!d1.empty())
        ans[d1.front()]=ml,d1.pop();
      while(!d2.empty())
        ans[d2.front()]=ml,d2.pop();
      return;
    }
    while(!d1.empty())
      cty[++gg]=d1.front(),d1.pop();
    mid=gg;
    while(!d2.empty())
      cty[++gg]=d2.front(),d2.pop();
    for(int i=ml;i<=midm;i++)
    {
        if(q[i].l<=q[i].r) modify(q[i].l,-q[i].a),modify(q[i].r+1,q[i].a);
        else modify(q[i].l,-q[i].a),modify(1,-q[i].a),modify(q[i].r+1,q[i].a);
    }
    if(mid>=ql) cdq(ml,midm,ql,mid);
    if(mid<gg) cdq(midm+1,mr,mid+1,gg);
}

int main()
{
    memset(head,-1,sizeof(head));
    n=readit();m=readit();
    for(int i=1;i<=m;i++)
      cty[i]=readit(),add(cty[i],i);
    for(int i=1;i<=n;i++)
      aim[i]=readit();
    cnt=0;int t=1;
    while(aim[t]!=0&&t<=n)
      cty[++cnt]=t,t++;
    k=readit();
    for(int i=1;i<=k;i++)
      q[i].l=readit(),q[i].r=readit(),q[i].a=readit();
    cdq(1,k,1,cnt);
    for(int i=1;i<=n;i++){
      if(ans[i]==-1) printf("NIE\n");
      else printf("%d\n",ans[i]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值