This way
有n个位置,每个位置上都有一些方块。每次有两种操作:
1 x 询问位置x有多少个方块
2 x y 将位置x y的方块向左移一格,并问你有多少个方块被推动
所有方块受力学的影响
为了这道题特意去学了FHQ Treap
很明显首先这道题是按照位置建树的,然后我们又需要支持以下操作:找到第x个位置左边的位置l使得min(a[l]~a[r])>=y
那么我们就要先将树分成x左右边两个部分,然后再找到左边的树的最后小于y的位置并且将树分成两部分。这里就需要两个split
然后的话对于移动,也就是a[l-1]加上a[l]-y+1,然后a[l]等于y-1,然后将l和l+1~r交换一下位置。那么就重新merge一下即可。
#include
using namespace std;
#define ll long long
const int N=2e5+5;
int ch[N][2];// 0左孩子 1右孩子
ll val[N];// 每一个点的权值
int pri[N];// 随机生成的附件权值
int siz[N];// 以i为节点的树的节点数量
int tot;// 总结点的数量
int f[N];//翻转标记
ll sum[N];//权值和
ll mi[N];//最小值
mt19937 rnd(time(NULL));
void update(int x){
siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];
mi[x]=val[x];
if(ch[x][0])mi[x]=min(mi[x],mi[ch[x][0]]);
if(ch[x][1])mi[x]=min(mi[x],mi[ch[x][1]]);
sum[x]=val[x]+sum[ch[x][0]]+sum[ch[x][1]];
}
unordered_map<int,int>fa;
int finds(int x){return fa.count(x)?fa[x]=finds(fa[x]):x;}
int newnode(ll v){
siz[++tot]=1;// 新开辟一个节点
val[tot]=mi[tot]=sum[tot]=v;
pri[tot]=finds(rnd());
fa[pri[tot]]=finds(pri[tot]+1);
return tot;
}
int merge(int x,int y){
if(!x||!y)return x+y;
if(pri[x]<pri[y]){
ch[x][1]=merge(ch[x][1],y);
update(x);
return x;
}
else {
ch[y][0]=merge(x,ch[y][0]);
update(y);
return y;
}
}
void split_siz(int rt,int k,int &x,int &y){
if(!rt)x=y=0;
else {
if(siz[ch[rt][0]]+1<=k)
x=rt,split_siz(ch[rt][1],k-siz[ch[rt][0]]-1,ch[rt][1],y);
else
y=rt,split_siz(ch[rt][0],k,x,ch[rt][0]);
update(rt);
}
}
void split_mi(int rt,int k,int &x,int &y){
if(!rt)x=y=0;
else {
if(mi[ch[rt][1]]<k||val[rt]<k)
x=rt,split_mi(ch[rt][1],k,ch[rt][1],y);
else
y=rt,split_mi(ch[rt][0],k,x,ch[rt][0]);
update(rt);
}
}
int kth(int rt,int k){
while(1){
if(k<=siz[ch[rt][0]])
rt=ch[rt][0];
else if(k==siz[ch[rt][0]]+1)
return rt;
else
k-=siz[ch[rt][0]]+1,rt=ch[rt][1];
}
}
ll get_v(int rt,int x){
return val[kth(rt,x)];
}
ll get_sum(int &rt,int x,int y){
if(get_v(rt,x)<y)return 0;
int t1,t2,t3,t4,t5;
split_siz(rt,x,t1,t2);
if(mi[t1]>=y){
rt=merge(t1,t2);
return 0;
}
split_mi(t1,y,t1,t3);
ll ans=sum[t3]-1ll*(y-1)*siz[t3];
//printf("sum: %lld,ans: %lld\n",sum[t3],ans);
split_siz(t1,siz[t1]-1,t1,t4);
split_siz(t3,1,t3,t5);
val[t4]+=val[t3]-y+1;
mi[t4]=sum[t4]=val[t4];
mi[t3]=sum[t3]=val[t3]=y-1;
rt=merge(merge(merge(merge(t1,t4),t5),t3),t2);
return ans;
}
int num,n,m;
void dfs(int rt){
//if(f[rt])push_down(rt);
if(ch[rt][0])dfs(ch[rt][0]);
num++;
printf("%lld%c",val[rt]," \n"[num==n]);
if(ch[rt][1])dfs(ch[rt][1]);
}
ll a[N];
int main()
{
int t;
scanf("%d",&t);
while(t--){
tot=0;
fa.clear();
memset(ch,0,sizeof(ch));
//mi[0]=2e9;
int rt=0;
num=0;
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)mi[i]=2e9;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),rt=merge(rt,newnode(a[i]));
//dfs(rt);
//printf("\n");
while(m--){
int op,x,y;
scanf("%d%d",&op,&x);
if(op-1){
printf("%lld\n",get_v(rt,x));
}
else {
scanf("%d",&y);
printf("%lld\n",get_sum(rt,x,y));
}
}
dfs(rt);
//printf("\n");
}
return 0;
}