对于每个询问,设不小于$s$的个数为$cnt$,小于$s$的和为$sum$。
那么如果可以进行$s$轮,当且仅当$sum\geq (c-cnt)\times s$。
权值线段树维护,时间复杂度$O(m\log m)$。
证明:
如果$cnt\geq c$,那么显然可以每次取$c$个。
否则如果$sum\geq (c-cnt)\times s$,那么小于$s$的个数必然不小于$c$,可以每次取最大的$c$个来完成。
当$sum<(c-cnt)\times s$时,那么无论怎么取,都是做不到$s$轮的。
#include<cstdio> #include<algorithm> const int N=1000010,M=2100000; int n,m,i,x,y,a[N],b[N],cb,op[N][3],v[M],cnt;long long s[M],sum; inline void read(int&a){char c;while(!(((c=getchar())>=‘0‘)&&(c<=‘9‘)));a=c-‘0‘;while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;} inline int lower(int x){ int l=1,r=cb,mid,t=cb+1; while(l<=r)if(b[mid=(l+r)>>1]>=x)r=(t=mid)-1;else l=mid+1; return t; } inline void ins(int c,int V,int S){ if(!c)return; int a=1,b=cb,x=1,mid; while(1){ v[x]+=V,s[x]+=S; if(a==b)return; mid=(a+b)>>1,x<<=1; if(c<=mid)b=mid;else a=mid+1,x++; } } inline void ask(int c){ int a=1,b=cb,x=1,mid; if(c>cb){cnt=0,sum=s[1];return;} cnt=v[1],sum=0; while(a<b){ mid=(a+b)>>1,x<<=1; if(c<=mid)b=mid;else cnt-=v[x],sum+=s[x],a=mid+1,x++; } } int main(){ read(n),read(m); for(i=1;i<=m;i++){ char ch; while((ch=getchar())!=‘U‘&&ch!=‘Z‘); op[i][0]=ch,read(op[i][1]),read(op[i][2]); if(ch==‘U‘)b[++cb]=op[i][2]; } std::sort(b+1,b+cb+1); for(i=1;i<=m;i++){ x=op[i][1],y=op[i][2]; if(op[i][0]==‘U‘){ ins(a[x],-1,-b[a[x]]); a[x]=lower(y); ins(a[x],1,y); }else{ ask(lower(y)); puts(sum>=1LL*(x-cnt)*y?"TAK":"NIE"); } } return 0; }
时间: 2024-10-13 05:44:37