Colorful Operations (CF2D) (线段树,对连续相同标记的一段进行lz的01处理+均摊思想+前缀和处理(用到才更新,不实时更新))

思路:
- 形式上就很像线段树, 在染色的时候, 关键是对相同颜色的权值一起加,
- 这个地方要用前缀和处理, 因为没有要求加一次就要实时更新, 于是就用到了在更新,如何更新呢? 就利用前缀和
- 然后 修改一个区间, 先把这个区间本来的颜色值更新,在减去当前的颜色值, 因为这个时候是从当时开始算的
- 而且这个修改内的区间颜色不同的时间复杂度是均摊的, 可以举例让每一次都是 1-n, 或者是 1,1, 2,2;
- 查找同理可得

#include <bits/stdc++.h> using namespace std; #define M 1000005 #define ri register int int n,m; long long val[M]; int col[M]; struct dian{ int col; int fg; long long val; long long lz; int l,r; }p[M*4]; void build(int i,int l,int r) { p[i].l=l,p[i].r=r;p[i].col=1; if(l==r) { p[i].col=1; return ; } int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); } void down(int i) { p[i].fg=0; p[i<<1].lz+=p[i].lz; p[i<<1|1].lz+=p[i].lz; p[i].lz=0; p[i<<1].col=p[i].col; p[i<<1|1].col=p[i].col; p[i<<1].fg=1; p[i<<1|1].fg=1; } void xiu(int i,int l,int r,int c) { if(l>p[i].r||r<p[i].l) return ; if(l<=p[i].l&&p[i].r<=r&&p[i].col) { p[i].lz+=val[p[i].col]; p[i].lz-=val[c]; p[i].col=c; p[i].fg=1; return ; } if(p[i].fg) down(i); xiu(i<<1,l,r,c); xiu(i<<1|1,l,r,c); if(p[i<<1].col==p[i<<1|1].col) p[i].col=p[i<<1].col; else p[i].col=0; } long long qu(int i,int l,int r) { if(l>p[i].r||r<p[i].l) return 0; if(l<=p[i].l&&p[i].r<=r) { col[p[i].l]=p[i].col; return p[i].lz; } if(p[i].fg) down(i); return qu(i<<1,l,r)+qu(i<<1|1,l,r); } int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>n>>m; build(1,1,n); for(ri i=1;i<=n;i++) col[i]=1; for(ri i=1;i<=m;i++) { string op; cin>>op; if(op=="Color") { int a,b,c; cin>>a>>b>>c; xiu(1,a,b,c); } if(op=="Add") { int a,b; cin>>a>>b; val[a]+=b; } if(op=="Query") { int a; cin>>a; long long tmp=qu(1,a,a); tmp+=val[col[a]]; cout<<tmp<<"\n"; } } return 0; }
后记:
- 线段树 是4 倍 空间