[POI2015]LOG

题目

发现询问是针对整个区间,也就是说位置什么用都没有

发现我们需要构造出\(s\)个长度为\(c\)的数列,每个数只能在一个数列中出现一次,且一个数最多的使用次数是其大小

对于那些大于等于\(s\)的数,我们让这些数在每一个数列里都出现就好了,如果这样的数有\(val\)个,相当于我们要构造的数列的长度变成了\(c-val\)

对于小于\(s\)的数我们可以让这些数在每一个数列里尽量出现,看一下这些数的和是否能充满剩下的\(s\times(c-val)\)个位置就好了

树状数组维护一下就好了

代码

#include<algorithm>
#include<cstdio>
#define LL long long
#define lowbit(i) ((i)&(-i))
#define re register
#define maxn 1000005
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,sz;
char opt[maxn][2];
int a[maxn],b[maxn],c[maxn],pos[maxn];
struct Bit {
    LL t[maxn];
    inline void add(int x,int val) {for(re int i=x;i<=sz;i+=lowbit(i)) t[i]+=val;}
    inline LL ask(int x) {LL now=0;for(re int i=x;i;i-=lowbit(i)) now+=t[i];return now;}
}B[2];
inline int find(int x) {
    int l=1,r=sz;
    while(l<=r) {
        int mid=l+r>>1;
        if(c[mid]==x) return mid;
        if(c[mid]>x) r=mid-1;else l=mid+1;
    }
    return 0;
}
int main() {
    n=read(),m=read();
    for(re int i=1;i<=m;i++) scanf("%s",opt[i]),a[i]=read(),b[i]=read(),c[i]=b[i];
    std::sort(c+1,c+m+1),sz=std::unique(c+1,c+m+1)-c-1;
    for(re int i=1;i<=m;i++) {
        int x=find(b[i]);
        if(opt[i][0]=='U') {
            if(pos[a[i]]) B[0].add(pos[a[i]],-1),B[1].add(pos[a[i]],-1*c[pos[a[i]]]);
            B[0].add(x,1),B[1].add(x,b[i]);pos[a[i]]=x;
        }
        else {
            a[i]-=B[0].ask(sz)-B[0].ask(x-1);
            if(a[i]<=0) {puts("TAK");continue;}
            if(B[1].ask(x-1)>=(LL)a[i]*(LL)b[i]) puts("TAK");
                else puts("NIE");
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10540626.html