P3863 序列 题解
Link.
Description.
维护序列,支持:
- 区间加
- 单点查询这个数历史版本有多少个 \(\le K\)
Solution.
只有第二个操作都需要一个树套树。
所以我们可以往 \(\sqrt\,\) 数据结构想。
但是这个分块方式是真的想不到。
考虑只有一个数的做法。
相当于要查询时间轴上有多少数 \(\le K\)
离线然后按照时间分块,查询直接二分就行了。
复杂度 \(O(Q\sqrt Q\log(\sqrt Q))=O(Q\sqrt Q\log Q)\)。
然后考虑多个数,可以离线处理关于每个数的询问。
可以考虑差分然后前缀和,从左往右扫,在 \(l\) 处 \(+v\),在 \(r+1\) 处 \(-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;
}