[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;
}
posted @ 2019-03-16 08:55  asuldb  阅读(387)  评论(0编辑  收藏  举报