洛谷 P3527 [POI2011]MET-Meteors 解题报告

P3527 [POI2011]MET-Meteors

题意翻译

\(\tt{Byteotian \ Interstellar \ Union}\)\(N\)个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为\(M\)份(第\(M\)份和第\(1\)份相邻),第\(i\)份上有第\(A_i\)个国家的太空站。 这个星球经常会下陨石雨。\(\tt{BIU}\)已经预测了接下来\(K\)场陨石雨的情况。 \(\tt{BIU}\)的第\(i\)个成员国希望能够收集\(P_i\)单位的陨石样本。你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。

输入

第一行是两个数\(N\),\(M\)。 第二行有\(M\)个数,第\(i\)个数\(O_i\)表示第\(i\)段轨道上有第\(O_i\)个国家的太空站。 第三行有\(N\)个数,第\(i\)个数\(P_i\)表示第\(i\)个国家希望收集的陨石数量。 第四行有一个数\(K\),表示\(\tt{BIU}\)预测了接下来的\(K\)场陨石雨。 接下来\(K\)行,每行有三个数\(L_i,R_i,A_i\),表示第\(K\)场陨石雨的发生地点在从\(L_i\)顺时针到\(R_i\)的区间中(如果\(L_i \le R_i\),就是\(L_i,L_{i+1},\dots,R_i\),否则就是\(R_i,R_{i+1},\dots,m-1,m,1,\dots,L_i\)),向区间中的每个太空站提供\(A_i\)单位的陨石样本。

输出

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

数据范围:

\(1\le n,m,k\le 3\times 10^5,1\le Pi\le 10^9,1\le Ai<10^9\)


整体二分,按时间二分陨石雨,划分一下国家。树状数组维护区间加单点查就行。

注意可能爆\(\tt{long \ long}\),边读边看多没多


Code:

// luogu-judger-enable-o2
#include <cstdio>
#include <vector>
#include <cctype>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int N=3e5+10;
ll read()
{
    ll x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x;
}
struct Q{int k,id;std::vector <int> pos;}q[N],ql[N],qr[N];;
struct node{int l,r;ll a;}op[N];
ll s[N];int ans[N],n,m,k;
void add(int x,ll d){while(x<=m)s[x]+=d,x+=x&-x;}
ll query(int x){ll sum=0;while(x)sum+=s[x],x-=x&-x;return sum;}
void divide(int l,int r,int s,int t)
{
    if(s>t) return;
    if(l==r){rep(i,s,t)ans[q[i].id]=l;return;}
    int mid=l+r>>1,lp=0,rp=0;
    rep(i,l,mid)
    {
        if(op[i].l<=op[i].r) add(op[i].l,op[i].a),add(op[i].r+1,-op[i].a);
        else add(1,op[i].a),add(op[i].r+1,-op[i].a),add(op[i].l,op[i].a);
    }
    rep(i,s,t)
    {
        ll c=0;
        for(int j=0;j<q[i].pos.size();j++)
        {
            c+=query(q[i].pos[j]);
            if(q[i].k<=c) {ql[++lp]=q[i];break;}
        }
        if(q[i].k>c)qr[++rp]=q[i],qr[rp].k-=(int)(c);
    }
    rep(i,l,mid)
    {
        if(op[i].l<=op[i].r) add(op[i].l,-op[i].a),add(op[i].r+1,op[i].a);
        else add(1,-op[i].a),add(op[i].r+1,op[i].a),add(op[i].l,-op[i].a);
    }
    rep(i,s,s+lp-1) q[i]=ql[i+1-s];
    rep(i,s+lp,t) q[i]=qr[i+1-s-lp];
    divide(l,mid,s,s+lp-1),divide(mid+1,r,s+lp,t);
}
int main()
{
    n=read(),m=read();
    rep(i,1,m) q[read()].pos.push_back(i);
    rep(i,1,n) q[i].k=read(),q[i].id=i;
    k=read();
    rep(i,1,k) op[i].l=read(),op[i].r=read(),op[i].a=read();
    op[++k]={1,1,0};
    divide(1,k,1,n);
    rep(i,1,n)
    {
        if(ans[i]==k) puts("NIE");
        else printf("%d\n",ans[i]);
    }
    return 0;
}

2018.11.3

转载于:https://www.cnblogs.com/butterflydew/p/9899676.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值