P3863 序列 題解
阿新 • • 發佈:2021-11-10
Link.
Description.
維護序列,支援:
- 區間加
- 單點查詢這個數歷史版本有多少個 \(\le K\)
Solution.
只有第二個操作都需要一個樹套樹。
所以我們可以往 \(\sqrt\,\) 資料結構想。
但是這個分塊方式是真的想不到。
考慮只有一個數的做法。
相當於要查詢時間軸上有多少數 \(\le K\)
離線然後按照時間分塊,查詢直接二分就行了。
複雜度 \(O(Q\sqrt Q\log(\sqrt Q))=O(Q\sqrt Q\log Q)\)。
然後考慮多個數,可以離線處理關於每個數的詢問。
可以考慮差分然後字首和,從左往右掃,在 \(l\) 處 \(+v\)
在時間上 \(+\) 操作可以轉化為時間軸上的字尾加,分塊是可以處理這件事的。
然後就做完了。
Coding.
點選檢視程式碼
//是啊……你就是那隻鬼了……所以被你碰到以後,就輪到我變成鬼了{{{ #include<bits/stdc++.h> using namespace std;typedef long long ll; template<typename T>inline void read(T &x) { x=0;char c=getchar(),f=0; for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1; for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48); f?x=-x:x; } template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}} const int N=100005,B=316;int n,m,a[N]; struct qry{int p,t,w;}q[N];int qt;ll rs[N]; struct chg{int p,t;ll v;}c[N<<2];int ct; namespace block { int n,bl[N],L[N/B+5],R[N/B+5],ln[N/B+5],blt; ll vl[N/B+5][B+5],tg[N/B+5],a[N]; inline void init() { n=::m;for(int i=0;i<=n;i++) bl[i]=i/B+1; for(int i=0;i<=n;i++) (L[bl[i]]?0:L[bl[i]]=i),R[bl[i]]=i; blt=bl[n];for(int i=1;i<=blt;i++) ln[i]=R[i]-L[i]+1; } inline int qrybl(int id,ll w) {return ln[id]-(lower_bound(vl[id]+1,vl[id]+ln[id]+1,w-tg[id])-vl[id])+1;} inline void pushdw(int id) { ll v;if(!tg[id]) return;else v=tg[id],tg[id]=0; for(int i=L[id];i<=R[id];i++) a[i]+=v; for(int i=1;i<=ln[id];i++) vl[id][i]+=v; } inline void rebuild(int id) { for(int i=L[id];i<=R[id];i++) vl[id][i-L[id]+1]=a[i]; sort(vl[id]+1,vl[id]+ln[id]+1); } inline int query(int l,int r,ll k) { if(l>r) return 0; int le=bl[l],ri=bl[r],rs=0;pushdw(le);if(le^ri) pushdw(ri); if(le==ri) {for(int i=l;i<=r;i++) rs+=(a[i]>=k);return rs;} for(int i=l;i<=R[le];i++) rs+=(a[i]>=k); for(int i=L[ri];i<=r;i++) rs+=(a[i]>=k); for(int i=le+1;i<ri;i++) rs+=qrybl(i,k); return rs; } inline void modif(int l,int r,ll k) { int le=bl[l],ri=bl[r];pushdw(le);if(le^ri) pushdw(ri); if(le==ri) {for(int i=l;i<=r;i++) a[i]+=k;return rebuild(le);} for(int i=l;i<=R[le];i++) a[i]+=k; for(int i=L[ri];i<=r;i++) a[i]+=k; for(int i=le+1;i<ri;i++) tg[i]+=k; rebuild(le),rebuild(ri); } } int main() { read(n,m),block::init(); for(int i=1;i<=n;i++) read(a[i]),c[++ct]=(chg){i,0,a[i]-a[i-1]}; for(int i=1,fg,l,r;i<=m;i++) { read(fg,l,r);ll w;if(!(fg&1)) q[++qt]=(qry){l,i,r}; else read(w),c[++ct]=(chg){l,i,w},c[++ct]=(chg){r+1,i,-w}; }memset(rs,-1,sizeof(rs)); sort(q+1,q+qt+1,[&](qry a,qry b){return a.p<b.p;}); sort(c+1,c+ct+1,[&](chg a,chg b){return a.p<b.p;}); for(int i=1,cc=1,qq=1;i<=n;i++) { while(c[cc].p==i) block::modif(c[cc].t,m,c[cc].v),cc++; while(q[qq].p==i) rs[q[qq].t]=block::query(0,q[qq].t-1,q[qq].w),qq++; } for(int i=1;i<=m;i++) if(~rs[i]) printf("%lld\n",rs[i]); return 0; }