题意:
开始有1~n种颜色在1~n的区间上,现在有两种操作:
1 a b c表示将a~b区间的颜色涂为c,区间内的每个点会累加上值|new颜色-old颜色|。
2 a b求出a~b区间内每个点的值的和。
思路:
线段树+lazy标志。这里设置三个变量sum表示所求值的和,col表示当前节点上的颜色,lazy表示累加的值。
#include<cstdio>
#include<cmath>
using namespace std;
typedef __int64 LL;
const int MAX=1e5+5;
LL sum[MAX<<2];
LL col[MAX<<2];
LL lazy[MAX<<2];
void PushUp(int rt){
if(col[rt<<1]==col[rt<<1|1]) col[rt]=col[rt<<1];
else col[rt]=0;
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void PushDown(int rt,int m){
if(col[rt]){
col[rt<<1]=col[rt<<1|1]=col[rt];
lazy[rt<<1]+=lazy[rt],lazy[rt<<1|1]+=lazy[rt];
sum[rt<<1]+=lazy[rt]*(LL)(m-(m>>1)),sum[rt<<1|1]+=lazy[rt]*(LL)(m>>1);
col[rt]=lazy[rt]=0;
}
}
void Build(int l,int r,int rt){
if(l==r){
sum[rt]=0;
col[rt]=l;
return;
}
int mid=(l+r)>>1;
Build(l,mid,rt<<1);
Build(mid+1,r,rt<<1|1);
PushUp(rt);
}
void UpDate(int L,int R,int c,int l,int r,int rt){
if(L<=l&&r<=R&&col[rt]){
sum[rt]+=abs(col[rt]-c)*(LL)(r-l+1);
lazy[rt]+=abs(col[rt]-c);
col[rt]=c;
return;
}
PushDown(rt,r-l+1);
int mid=(l+r)>>1;
if(L<=mid) UpDate(L,R,c,l,mid,rt<<1);
if(mid<R) UpDate(L,R,c,mid+1,r,rt<<1|1);
PushUp(rt);
}
LL Query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return sum[rt];
}
PushDown(rt,r-l+1);
LL res=0;
int mid=(l+r)>>1;
if(L<=mid) res+=Query(L,R,l,mid,rt<<1);
if(mid<R) res+=Query(L,R,mid+1,r,rt<<1|1);
return res;
}
int main(){
int n,m,op,a,b,c;
scanf("%d%d",&n,&m);
Build(1,n,1);
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&a,&b,&c);
UpDate(a,b,c,1,n,1);
}
else{
scanf("%d%d",&a,&b);
printf("%I64d\n",Query(a,b,1,n,1));
}
}
return 0;
}