Description
KyleYoung买了n个五彩缤纷的气球,为了纪念OJ上的“刷漆”这道题,他决定给这些气球刷漆.(=.=||)
现在这n个气球排成了一排,编号为1~n,每个气球的颜色用一个正整数表示,初始时第i个气球的颜色为i.
每个气球都有一个“美丽值”,初始时每个气球美丽值都为0.如果一个气球当前的颜色为x,将它刷成颜色y时它的美丽值会增加|x-y|,然后它的颜色将变为y.
KyleYoung接下来进行了m次操作,操作有以下两种类型:
1.把编号在区间[L,R]内的气球颜色都染成x.
2.询问编号在区间[L,R]内的气球的美丽值之和.
现在请你帮帮KyleYoung回答这些询问…
Solution
KyleYoung比较忙ShinFeb比较懒所以我来写题解==
这题比较坑坑掉了我2h
首先本来以为是什么差分前缀和,后来下定决心写了个水分代码
思路如下:
用线段树来维护答案以及颜色。
然后更新的时候脑洞大开:
我们只找到颜色相同的一段区间才更新。
意识流的来看,好像不会T
听说CF上有人证明了这个更新是两个log的orz老外
总之就是莫名其妙敲水分代码一不小心敲了标程
Code
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
const int M=1e5+5;
typedef long long ll;
inline int Abs(int x){return x>0?x:-x;}
struct Segment_Tree{
struct node{
int l,r,clr;//clr表示一段区间的颜色,如果这段区间颜色不相同那么clr=-1
ll sum,dlt;
/*sum是答案,dlt是每个用来传给子节点的Σabs(颜色变化) (注意不可以直接往子节点上传当前更新的颜色
因为这样的话假设一段区间颜色为4,先把这段区间改成7,再改成3,就错了)
*/
bool f;//f=1:包含的区间颜色相同,f=0:颜色不同
}tree[M<<2];
inline void up(int p){
if(tree[p<<1].f&&tree[p<<1|1].f&&tree[p<<1].clr==tree[p<<1|1].clr)
tree[p].f=1,tree[p].clr=tree[p<<1].clr;
else tree[p].f=0,tree[p].clr=-1;
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}
inline void down(int &p){
if(!tree[p].dlt)return;
tree[p<<1].dlt+=tree[p].dlt,tree[p<<1|1].dlt+=tree[p].dlt;
tree[p<<1].sum+=1ll*tree[p].dlt*(tree[p<<1].r-tree[p<<1].l+1);
tree[p<<1|1].sum+=1ll*tree[p].dlt*(tree[p<<1|1].r-tree[p<<1|1].l+1);
tree[p<<1].clr=tree[p<<1|1].clr=tree[p].clr;
tree[p].dlt=0;
}
void build(int l,int r,int p=1){
tree[p].l=l,tree[p].r=r,tree[p].f=tree[p].sum=tree[p].dlt=0;
if(l==r){
tree[p].f=1,tree[p].clr=l;
tree[p].sum=0,tree[p].dlt=0;
return;
}
int mid=l+r>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
}
void update(int l,int r,const int &c,int p=1){
if(tree[p].l==l&&tree[p].r==r&&tree[p].f){//当区间吻合且颜色相同时
tree[p].sum+=1ll*Abs(c-tree[p].clr)*(tree[p].r-tree[p].l+1);
tree[p].f=1,tree[p].dlt+=Abs(c-tree[p].clr),tree[p].clr=c;
return;
}
down(p);
int mid=tree[p].l+tree[p].r>>1;
if(r<=mid)update(l,r,c,p<<1);
else if(l>mid)update(l,r,c,p<<1|1);
else update(l,mid,c,p<<1),update(mid+1,r,c,p<<1|1);
up(p);
}
ll query(int l,int r,int p=1){
if(tree[p].l==l&&tree[p].r==r)return tree[p].sum;//单纯地查找答案
down(p);
int mid=tree[p].l+tree[p].r>>1;
if(r<=mid)return query(l,r,p<<1);
if(l>mid)return query(l,r,p<<1|1);
return query(l,mid,p<<1)+query(mid+1,r,p<<1|1);
}
}T;
inline void rd(int &a){
a=0;char c;
while(c=getchar(),!isdigit(c));
do a=a*10+(c^48);
while(c=getchar(),isdigit(c));
}
inline void work(ll x){
if(!x)return;
work(x/10);
printf("%d",x%10);
}
inline void print(ll x){
if(x==0)putchar('0');
else work(x);
putchar('\n');
}
int main(){
freopen("paintagain.in","r",stdin);
freopen("paintagain.out","w",stdout);
int n,m;cin>>n>>m;
T.build(1,n);
for(int f,l,r,x;m--;){
rd(f),rd(l),rd(r);
switch(f){
case(1):rd(x),T.update(l,r,x);break;
case(2):print(T.query(l,r));break;
}
}
return 0;
}