给一个方块的序列 b i bi bi ,如下图。有 q q q 次询问,每次有两种操作,一种操作为 ( x , y ) (x,y) (x,y) ,表示从第 x x x 列的 y y y 的方格的位置向左移一格,同时将上面的都会带动,并且若左边有方块则也依次向左移,若 y y y 是空的,或者移出边界,则不移动。第二种操作,则是查询第 x x x 列的方块个数。
对于 1 1 1 操作,若设 l l l 为最大的位置使得 m i n { b [ l ] 到 b [ x ] } > = y min\{b[l] 到 b[x]\}>=y min{b[l]到b[x]}>=y ,若 l = 1 l=1 l=1 则不操作,否则此时 b [ l − 1 ] b[l-1] b[l−1] 的值为 b [ l − 1 ] + b [ l ] − y + 1 b[l-1]+b[l]-y+1 b[l−1]+b[l]−y+1 , b [ l ] b[l] b[l] 到 b [ x − 1 ] b[x-1] b[x−1] 的值,应该都等于后面位置的值, b [ x ] b[x] b[x] 的值就变成 y − 1 y-1 y−1 ,相当于将 b [ l ] = y − 1 b[l]=y-1 b[l]=y−1 ,并且将 b [ l ] b[l] b[l] 和 b [ l + 1 ] b[l+1] b[l+1] 到 b [ x ] b[x] b[x] 这一段交换位置。这些操作就可以使用平衡树来实现,下面代码使用 f h q t r e a p fhq_treap fhqtreap 实现,其中 s p i l t spilt spilt _ r r r _ m i n ( ) min() min() 为核心操作,可以得到 l l l 的值。
#include
#define ll long long
using namespace std;
const int N=5e5+10;
int T,n,q;
int b[N];
int x,y;
int ans[N];
mt19937 rnd(13331);
struct fhq_treap{
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
int sz[N],mi[N],val[N],ch[N][2],key[N];
ll sum[N];
int cnt,root;
void init() { //要初始化
for(int i=0;i<=n+1;i++) ls(i)=rs(i)=0;
cnt=0;mi[0]=1e9+7;
}
inline void up(int o) {
sz[o]=sz[ls(o)]+sz[rs(o)]+1;
sum[o]=sum[ls(o)]+sum[rs(o)]+val[o];
mi[o]=min(val[o],min(mi[ls(o)],mi[rs(o)]));
}
inline int built(int *a,int l,int r) { //直接构建
if(l>r) return 0;
int now=++cnt;
int mid=(l+r)/2;
sum[now]=mi[now]=val[now]=a[mid];
sz[now]=(r-l+1);key[now]=rnd();
ls(now)=built(a,l,mid-1);
rs(now)=built(a,mid+1,r);
up(now);
return now;
}
inline void spilt(int o,int siz,int &x,int &y) { //按大小分
if(o==0) {x=y=0; return;}
if(sz[ls(o)]<siz) {
x=o;spilt(rs(o),siz-sz[ls(o)]-1,rs(o),y);
}else {
y=o;spilt(ls(o),siz,x,ls(o));
}
up(o);
}
inline void spilt_r_min(int o,int v,int &x,int &y) { //重要操作,将大于等于v的分到y树上,其余分到x树上
if(o==0) {x=y=0;return ;}
if(mi[rs(o)]<v || val[o]<v) {
x=o;spilt_r_min(rs(o),v,rs(o),y);
}else {
y=o;spilt_r_min(ls(o),v,x,ls(o));
}
up(o);
}
inline int merge(int x,int y) {
if(x==0||y==0) return x+y;
if(key[x]>key[y]) {
rs(x)=merge(rs(x),y);up(x);
return x;
}else {
ls(y)=merge(x,ls(y));up(y);
return y;
}
return -1;
}
inline int getnum(int pos) {
int now=root;
while(sz[ls(now)]+1!=pos) {
if(pos>sz[ls(now)]+1) {
pos-=sz[ls(now)]+1;
now=rs(now);
}else now=ls(now);
}
return val[now];
}
inline ll getsum(int x,int y) {
if(getnum(x)<y) return 0;
int t1,t2,t3,t4,t5;
spilt(root,x,t1,t2);
if(mi[t1]>=y) {
root=merge(t1,t2);
return 0;
}
spilt_r_min(t1,y,t1,t3);
ll res=sum[t3]-1ll*(y-1)*sz[t3]; //统计移动个数
spilt(t1,sz[t1]-1,t1,t4);
//t1+t4+t3+t5+t2
spilt(t3,1,t3,t5);
val[t4]+=val[t3]-y+1;
mi[t4]=sum[t4]=val[t4];
val[t3]=mi[t3]=sum[t3]=y-1;
//t1+t4+t5+t3+t2
root=merge(merge(merge(merge(t1,t4),t5),t3),t2);
return res;
}
}treap;
int main()
{
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&q);
treap.init();
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
treap.root=treap.built(b,1,n);
while(q--) {
int op;
scanf("%d",&op);
if(op==1) {
scanf("%d%d",&x,&y);
printf("%lld\n",treap.getsum(x,y));
}else {
scanf("%d",&x);
int gs=treap.getnum(x);
printf("%d\n",gs);
}
}
for(int i=1;i<=n;i++) printf("%d%c",treap.getnum(i),i==n?'\n':' ');
}
}