NOIP2017列队( 二 )


第一个难点,线段树的二分结构使得我们可以边二分边求前缀和,做到复杂度O(logn),但是树状数组在蒟蒻的眼中一般来说都只能二分套树状数组O(log^2n),这复杂度首先就不对了 。
树状数组也是可以O(logn)并且常数更小的完成这个任务的 。
如果你学习过zkw线段树,你可以发现树状数组就是一个省了一半空间的线段树加上中序遍历 。
实际上还是可以实现的,具体看代码 。
第二个难点,树状数组不能动态开点 。
但是你会发现,其实我们需要维护的信息,因为我们是惰性删除,我们只需要求实际的位置就可以,而这针对于各行各列都是相对独立的,那么完全没有必要一遍求出答案,每一行分别处理,最后利用最后一列求出答案就行 。
AC Code(50行尚可):
【NOIP2017列队】#define maxn 300005#define LL long longusing namespace std;char cb[1<<15],*cs,*ct;#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)inline void read(int &res){ char ch;for(;!isdigit(ch=getc()););for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0'); }int n,m,q;int siz,tr[maxn*4],x[maxn],y[maxn],ry[maxn];vectorvec[maxn],qry[maxn];inline void upd(int now,int val){ for(;now<=siz;now+=now&-now) tr[now]+=val; }inline int qsum(int now){ int ret = 0;for(;now;now-=now&-now) ret+=tr[now];return ret; }inline int Find(int x){int ret=1,sum=0;for(;;ret<<=1) if((ret<<1)-tr[ret<<1]>=x) break;if(ret-tr[ret] == x) return ret;sum = tr[ret];for(int k=ret>>1;k;k>>=1) if((ret+k)-tr[ret+k]-sum