CF444C线段树+剪枝
题目描述
题目大意:给出一个长度为 n 的数组 a 和计算贡献的数组 sum,需要执行 m 次操作,每次操作分为下列两种类型:
1 l r x:将区间 [ l , r ] 内的 a 用 x 覆盖,即 i ∈[ l , r] , a[ i ] = x,且 sum[ i ] += abs( a[ i ] - x )
2 l r:询问区间 [ l , r ] 内的 sum 数组之和
题目解析
修改时直接将元素相同的区间统一处理即可。如果一个一个节点的去操作,肯定会超时但是一段序列中颜色不同的时候又不能进行区间更新。我们就设置一个数组去按着线段树更新的样子去记录每一段区间里颜色。只有序列颜色一样了才去更新这一区间
Code
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=5e6+100; struct node{ int l,r; ll sum,col,lazy; }t[maxn]; void push_up(int p){ t[p].sum=(t[2*p].sum+t[2*p+1].sum); t[p].col=(t[2*p].col==t[2*p+1].col?t[2*p].col:0); } void push_down(int p){ if(t[p].lazy){ t[2*p].lazy+=t[p].lazy; t[2*p+1].lazy+=t[p].lazy; t[2*p].sum+=1ll*(t[2*p].r-t[2*p].l+1)*t[p].lazy; t[2*p+1].sum+=1ll*(t[2*p+1].r-t[2*p+1].l+1)*t[p].lazy; t[2*p].col=t[2*p+1].col=t[p].col; t[p].lazy=0; } } void build(int p,int l,int r){ t[p].l=l,t[p].r=r; t[p].sum=t[p].lazy=t[p].col=0; if(l==r){ t[p].col=1ll*l; return ; } int mid=(l+r)/2; build(2*p,l,mid); build(2*p+1,mid+1,r); push_up(p); } void update(int p,int l,int r,ll x){ if(t[p].l>=l&&t[p].r<=r&&t[p].col){ t[p].sum+=1ll*abs(x-t[p].col)*(t[p].r-t[p].l+1); t[p].lazy+=1ll*abs(x-t[p].col); t[p].col=x; return ; } push_down(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid){ update(2*p,l,r,x); } if(r>mid){ update(2*p+1,l,r,x); } push_up(p); } ll query(int p,int l,int r){ if(t[p].l>=l&&t[p].r<=r){ return t[p].sum; } ll sum=0; push_down(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid){ sum+=query(2*p,l,r); } if(r>mid){ sum+=query(2*p+1,l,r); } return sum; } int n,m; int main(){ scanf("%d%d",&n,&m); build(1,1,n); int x,y,op; ll z; while(m--){ scanf("%d",&op); if(op==1){ scanf("%d%d%lld",&x,&y,&z); update(1,x,y,z); } else{ scanf("%d%d",&x,&y); printf("%lld\n",query(1,x,y)); } } }