C88 两个树状数组 P3586 [POI2015] LOG
视频链接:C88 两个树状数组 P3586 [POI2015] LOG_哔哩哔哩_bilibili
// 两个树状数组 O(nlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; void read(int &x){ x=0;char c=getchar(); while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') x=x*10+c-'0',c=getchar(); } #define LL long long #define N 1000005 #define lowb(x) x&-x int n,m;char op[N]; int c[N],s[N],b[N],p[N]; LL cnt,sum,tr1[N],tr2[N]; //tr1种类数,tr2数量和 void change(LL*s,int x,int k){ //向后修 while(x<=m) s[x]+=k,x+=lowb(x); } LL query(LL*s,int x){ //向前查 LL t=0; while(x) t+=s[x],x-=lowb(x); return t; } int main(){ read(n),read(m); for(int i=1;i<=m;++i) scanf(" %c",&op[i]),read(c[i]),read(s[i]),b[i]=s[i]; sort(b+1,b+m+1); //离散化 for(int i=1;i<=n;++i) p[i]=m+1; //无用位置 for(int i=1,si,k;i<=m;++i){ if(op[i]=='U'){ k=c[i]; //修改值的下标 si=lower_bound(b+1,b+m+1,s[i])-b; //修改值的离散值 change(tr1,si,1); //加上新种类数的贡献 change(tr1,p[k],-1); //减去旧种类数的贡献 change(tr2,si,b[si]); //加上新数量的贡献 change(tr2,p[k],-b[p[k]]); //减去旧数量的贡献 p[k]=si; //记录第k个数的离散值 } else{ si=lower_bound(b+1,b+m+1,s[i])-b; //高度的离散值 cnt=query(tr1,m)-query(tr1,si-1); //>=s的种类数 sum=query(tr2,si-1); //<s的数量和 printf("%s\n",sum>=(c[i]-cnt)*s[i]?"TAK":"NIE"); } } }