题意:
思路:
类似于线段树维护标记。
区间赋值,优先级最高,直接对和进行维护。
区间加等差数列就可以把标记设为 :首项和公差,这样区间加等差数列的标记就能合并了。
再套平衡树就好了。
ops:
第一道比赛中做的平衡树的题。
因为当时状态比较拉跨,并且区间加等差数列的标记和之前一个线段树加等差数列的平方 的标记搞混了,觉得不能做。知道标记的维护方式,那他就成了裸裸的模板题了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=300010,INF=1e9;
ll n,m;
struct node{
ll vis[2],v,rnd,siz;
ll sum;
ll laz;
ll fir,sec;
}tree[maxn];
int tot=0,root=0;
void update(int x){
tree[x].siz=tree[tree[x].vis[0]].siz+tree[tree[x].vis[1]].siz+1;
tree[x].sum=tree[tree[x].vis[0]].sum+tree[tree[x].vis[1]].sum+tree[x].v;
}
void pushdown1(int x){
if(tree[x].laz==0)return;
if(tree[x].vis[0]){
tree[tree[x].vis[0]].laz=tree[x].laz;
tree[tree[x].vis[0]].sum=tree[x].laz*tree[tree[x].vis[0]].siz;
tree[tree[x].vis[0]].v=tree[x].laz;
tree[tree[x].vis[0]].fir=tree[tree[x].vis[0]].sec=0;
}
if(tree[x].vis[1]){
tree[tree[x].vis[1]].laz=tree[x].laz;
tree[tree[x].vis[1]].sum=tree[x].laz*tree[tree[x].vis[1]].siz;
tree[tree[x].vis[1]].v=tree[x].laz;
tree[tree[x].vis[1]].fir=0;
tree[tree[x].vis[1]].sec=0;
}
tree[x].laz=0;
}
void pushdown2(int x){
if(tree[x].fir==0)return ;
if(tree[x].vis[0]){
tree[tree[x].vis[0]].fir+=tree[x].fir;
tree[tree[x].vis[0]].sec+=tree[x].sec;
int z=tree[tree[x].vis[0]].vis[0];
tree[tree[x].vis[0]].v+=tree[x].fir+tree[x].sec*(tree[z].siz);
tree[tree[x].vis[0]].sum+=(2*tree[x].fir+tree[x].sec*(tree[tree[x].vis[0]].siz-1))*tree[tree[x].vis[0]].siz/2;
}
if(tree[x].vis[1]){
ll fir=tree[x].fir+tree[x].sec*(tree[tree[x].vis[0]].siz+1);
tree[tree[x].vis[1]].fir+=fir;
tree[tree[x].vis[1]].sec+=tree[x].sec;
int z=tree[tree[x].vis[1]].vis[0];
tree[tree[x].vis[1]].v+=fir+tree[x].sec*(tree[z].siz);
tree[tree[x].vis[1]].sum+=(2*fir+tree[x].sec*(tree[tree[x].vis[1]].siz-1))*tree[tree[x].vis[1]].siz/2;
}
tree[x].fir=tree[x].sec=0;
}
int newnode(ll v){
tot++;
tree[tot].siz=1;
tree[tot].v=v;
tree[tot].rnd=rand();
tree[tot].sum=v;
tree[tot].laz=0;tree[tot].fir=0;
tree[tot].sec=0;
return tot;
}
int merge(int x,int y){//默认x<y
if(!x||!y)return x+y;
if(tree[x].rnd<tree[y].rnd){
pushdown1(x);
pushdown2(x);
tree[x].vis[1]=merge(tree[x].vis[1],y);
update(x);
return x;
}else{
pushdown1(y);
pushdown2(y);
tree[y].vis[0]=merge(x,tree[y].vis[0]);
update(y);
return y;
}
}
void split2(int now,int k,ll &x,ll &y){//按siz分(找第k大
if(!now)x=y=0;
else {
pushdown1(now);
pushdown2(now);
if(k<=tree[tree[now].vis[0]].siz)
y=now,split2(tree[now].vis[0],k,x,tree[now].vis[0]);
else x=now,split2(tree[now].vis[1],k-tree[tree[now].vis[0]].siz-1,tree[now].vis[1],y);
update(now);
}
}
void insert(int v){
ll x,y;
split2(root,v,x,y);
ll a;
cin>>a;
root=merge(merge(x,newnode(a)),y);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)insert(i);
while(m--){
ll op,x,y,w;
cin>>op;
if(op==1){
cin>>x>>y>>w;
ll a,b,c;
split2(root,y,a,b);
split2(a,x-1,a,c);
tree[c].laz=w;
tree[c].v=w;
tree[c].sum=w*tree[c].siz;
root=merge(merge(a,c),b);
}else if(op==2){
cin>>x>>y>>w;
ll a,b,c;
split2(root,y,a,b);
split2(a,x-1,a,c);
tree[c].fir+=w;
tree[c].v+=w+w*(tree[tree[c].vis[0]].siz);
tree[c].sec+=w;
tree[c].sum+=(w+w*(tree[c].siz-1))*tree[c].siz/2;
root=merge(merge(a,c),b);
}else if(op==3){
cin>>w;
insert(w-1);
}else{
cin>>x>>y;
ll a,b,c;
split2(root,y,a,b);
split2(a,x-1,a,c);
printf("%lld\n",tree[c].sum);
root=merge(merge(a,c),b);
}
}
return 0;
}