题意:
有n个格子,一开始第i个格子的颜色为i,权值为0。
现在要进行m次操作,操作有两种:
(1,l,r,x)将区间[l,r]的所有格子修改为x颜色,如果一个格子之前的颜色是y,那么权值增加abs(x-y)
(2,l,r)计算区间[l,r]的权值和
数据范围:n,m<=1e5,x<=1e8
解法:
线段树
如果待修改区间的颜色相同,那么就可以整块一起维护,
如果不相同,似乎没办法一起维护,那么递归找相同颜色的子区间。
开一个颜色标记维护区间颜色是否相同以及记录颜色就行了。
颜色覆盖需要开一个颜色laz标记进行颜色下传
因为还需要维护权值,所以还需要一个权值laz标记进行权值下传
区间和是基本的区间和标记
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
int sum[maxm<<2];
int add[maxm<<2];
int col[maxm<<2];
int a[maxm<<2];
int n,m;
void pushup(int node){
if(a[node*2]&&a[node*2+1]&&a[node*2]==a[node*2+1]){
a[node]=a[node*2];
}else{
a[node]=0;
}
sum[node]=sum[node*2]+sum[node*2+1];
}
void pushdown(int node,int l,int r){
if(col[node]){//颜色修改标记
a[node*2]=col[node];
a[node*2+1]=col[node];
col[node*2]=col[node];
col[node*2+1]=col[node];
col[node]=0;
}
if(add[node]){//权值累加标记
int mid=(l+r)/2;
sum[node*2]+=add[node]*(mid-l+1);
sum[node*2+1]+=add[node]*(r-mid);
add[node*2]+=add[node];
add[node*2+1]+=add[node];
add[node]=0;
}
}
void build(int l,int r,int node){
if(l==r){
a[node]=l;return ;
}
int mid=(l+r)/2;
build(l,mid,node*2);
build(mid+1,r,node*2+1);
pushup(node);
}
void update(int st,int ed,int val,int l,int r,int node){
if(st<=l&&ed>=r&&a[node]){
sum[node]+=abs(val-a[node])*(r-l+1);
add[node]+=abs(val-a[node]);//权值下传只需要下传差值就行了
a[node]=val;
col[node]=val;
return ;
}
pushdown(node,l,r);
int mid=(l+r)/2;
if(st<=mid)update(st,ed,val,l,mid,node*2);
if(ed>mid)update(st,ed,val,mid+1,r,node*2+1);
pushup(node);
}
int ask(int st,int ed,int l,int r,int node){
if(st<=l&&ed>=r)return sum[node];
pushdown(node,l,r);
int mid=(l+r)/2;
int ans=0;
if(st<=mid)ans+=ask(st,ed,l,mid,node*2);
if(ed>mid)ans+=ask(st,ed,mid+1,r,node*2+1);
return ans;
}
signed main(){
cin>>n>>m;
build(1,n,1);
while(m--){
int op;cin>>op;
if(op==1){
int l,r,x;cin>>l>>r>>x;
update(l,r,x,1,n,1);
}else{
int l,r;cin>>l>>r;
int ans=ask(l,r,1,n,1);
cout<<ans<<endl;
}
}
return 0;
}