[POI2015]Logistyka

[POI2015]Logistyka

题目大意:

一个长度为\(n(n\le10^6)\)的数列\(A_i\),初始全为\(0\)。操作共\(m(m\le10^6)\)次,包含以下两种:

  1. \(A_x\)修改为\(y\)
  2. 询问若每次任意选择\(x\)个正数,将它们\(-1\),能否操作\(y\)次。

思路:

\(cnt\)表示不小于\(y\)的数的个数,\(sum\)表示小于\(y\)的数之和。

一个结论是,当\(sum\ge(x-cnt)\times y\)时可行,否则不可行。

证明参考Claris博客

时间复杂度\(\mathcal O(m\log n)\)

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
inline char getalpha() {
    register char ch;
    while(!isalpha(ch=getchar()));
    return ch;
}
const int N=1e6+1,M=1e6;
typedef long long int64;
struct Query {
    bool opt;
    int x,y;
};
Query q[M];
int tmp[N],w[N];
class SegmentTree {
    #define _left <<1
    #define _right <<1|1
    #define mid ((b+e)>>1)
    private:
        int64 val[2][N<<2],*cnt,*sum;
        void push_up(const int &p) {
            cnt[p]=cnt[p _left]+cnt[p _right];
            sum[p]=sum[p _left]+sum[p _right];
        }
    public:
        SegmentTree() {
            cnt=val[0];
            sum=val[1];
        }
        void modify(const int &p,const int &b,const int &e,const int &x,const int &y) {
            if(b==e) {
                cnt[p]+=y;
                sum[p]+=tmp[x]*y;
                return;
            }
            if(x<=mid) modify(p _left,b,mid,x,y);
            if(x>mid) modify(p _right,mid+1,e,x,y);
            push_up(p);
        }
        int64 query(const int &p,const int &b,const int &e,const int &l,const int &r,const bool &t) const {
            if(b==l&&e==r) return val[t][p];
            int64 ret=0;
            if(l<=mid) ret+=query(p _left,b,mid,l,std::min(mid,r),t);
            if(r>mid) ret+=query(p _right,mid+1,e,std::max(mid+1,l),r,t);
            return ret;
        }
    #undef _left
    #undef _right
    #undef mid
};
SegmentTree t;
int main() {
    const int n=getint(),m=getint();
    for(register int i=0;i<m;i++) {
        const char opt=getalpha();
        const int x=getint(),y=getint();
        q[i]=(Query){opt=='Z',x,y};
        tmp[++tmp[0]]=y;
    }
    std::sort(&tmp[1],&tmp[tmp[0]]+1);
    tmp[0]=std::unique(&tmp[1],&tmp[tmp[0]]+1)-&tmp[1];
    for(register int i=0;i<m;i++) {
        q[i].y=std::lower_bound(&tmp[1],&tmp[tmp[0]]+1,q[i].y)-tmp;
        const int &x=q[i].x,&y=q[i].y;
        if(q[i].opt) {
            const int cnt=t.query(1,1,tmp[0],y,tmp[0],0);
            const int64 sum=y!=1?t.query(1,1,tmp[0],1,y-1,1):0;
            puts(sum>=(int64)(x-cnt)*tmp[y]?"TAK":"NIE");
        } else {
            if(w[x]) t.modify(1,1,tmp[0],w[x],-1);
            w[x]=y;
            if(w[x]) t.modify(1,1,tmp[0],w[x],1);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/skylee03/p/9573091.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值