HDU 3397 Sequence operation 多标记线段树
Posted yanlifneg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 3397 Sequence operation 多标记线段树相关的知识,希望对你有一定的参考价值。
/* 一开始维护了两个标记 开了两个数组 想的是 可能当前两种操作都要做 但是太复杂了 不好处理 其实 当前要做的标记可以只有一个 我们在Insert的时候 要打的标记是2即翻转区间: 1.如果原来是区间赋值1 先赋值1在翻转 问题不大 标记变 1-1=0 2.如果原来是区间赋值0 同上 问题不大 标记 1-0=1 3.如果原始是区间翻转 抵消1-2=-1 4.如果原来是-1 无标记 就打上 1-(-1)=2 这个时候要先把区间的01信息互换 要打的标记是01即区间赋值 就无视之前的翻转操作 直接打上标记更新k 然后Up的时候(标记下方)就只有一个标记 1.如果是2 就下放 改了左右儿子 然后同上进行标记改变 2.如果是01 */ #include<cstdio> #include<cstring> #include<iostream> #define lc k*2 #define rc k*2+1 #define len (r-l+1) #define mid (l+r)/2 #define maxn 400010 using namespace std; int T,I,n,m,s1[maxn],s0[maxn],l1[maxn],l0[maxn],r1[maxn],r0[maxn],mx1[maxn],mx0[maxn],a[maxn]; void Swap(int k,int l,int r){ a[k]=1-a[k];swap(s1[k],s0[k]);swap(l1[k],l0[k]); swap(r1[k],r0[k]);swap(mx1[k],mx0[k]); } void Up(int k,int l,int r){ if(a[k]==2){ a[k]=-1;Swap(lc,l,mid);Swap(rc,mid+1,r);return; } a[lc]=a[rc]=a[k]; s1[lc]=(mid-l+1)*a[k];s0[lc]=(mid-l+1)*(a[k]^1); s1[rc]=(r-mid)*a[k];s0[rc]=(r-mid)*(a[k]^1); l1[lc]=(mid-l+1)*a[k];l0[lc]=(mid-l+1)*(a[k]^1); l1[rc]=(r-mid)*a[k];l0[rc]=(r-mid)*(a[k]^1); r1[lc]=(mid-l+1)*a[k];r0[lc]=(mid-l+1)*(a[k]^1); r1[rc]=(r-mid)*a[k];r0[rc]=(r-mid)*(a[k]^1); mx1[lc]=(mid-l+1)*a[k];mx0[lc]=(mid-l+1)*(a[k]^1); mx1[rc]=(r-mid)*a[k];mx0[rc]=(r-mid)*(a[k]^1); a[k]=-1; } void Insert(int k,int l,int r,int x,int y,int z){ if(x<=l&&y>=r){ if(z==2)Swap(k,l,r); else { a[k]=z;s1[k]=len*z;s0[k]=len*(z^1);mx1[k]=len*z;mx0[k]=len*(z^1); l1[k]=len*z;l0[k]=len*(z^1);r1[k]=len*z;r0[k]=len*(z^1); } return; } if(a[k]!=-1)Up(k,l,r); if(x<=mid)Insert(lc,l,mid,x,y,z); if(y>mid)Insert(rc,mid+1,r,x,y,z); s1[k]=s1[lc]+s1[rc];s0[k]=s0[lc]+s0[rc]; l1[k]=l1[lc]+(l1[lc]==mid-l+1)*l1[rc]; r1[k]=r1[rc]+(r1[rc]==r-mid)*r1[lc]; l0[k]=l0[lc]+(l0[lc]==mid-l+1)*l0[rc]; r0[k]=r0[rc]+(r0[rc]==r-mid)*r0[lc]; mx1[k]=max(mx1[lc],max(mx1[rc],r1[lc]+l1[rc])); mx0[k]=max(mx0[lc],max(mx0[rc],r0[lc]+l0[rc])); } int Query1(int k,int l,int r,int x,int y){ if(x<=l&&y>=r)return s1[k]; int res=0; if(a[k]!=-1)Up(k,l,r); if(x<=mid)res+=Query1(lc,l,mid,x,y); if(y>mid)res+=Query1(rc,mid+1,r,x,y); return res; } int Query2(int k,int l,int r,int x,int y){ if(x<=l&&y>=r)return mx1[k]; if(a[k]!=-1)Up(k,l,r); int res=0; if(x<=mid)res=max(res,Query2(lc,l,mid,x,y)); if(y>mid)res=max(res,Query2(rc,mid+1,r,x,y)); if(x<=mid&&y>mid)res=max(res,min(mid-x+1,r1[lc])+min(y-mid,l1[rc])); return res; } int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m);int x,y,z; for(int i=1;i<=n*4;i++)a[i]=-1; for(int i=1;i<=n;i++){ scanf("%d",&x);Insert(1,1,n,i,i,x); } for(I=1;I<=m;I++){ scanf("%d%d%d",&z,&x,&y);x++;y++; if(z==0||z==1||z==2)Insert(1,1,n,x,y,z); if(z==3)printf("%d ",Query1(1,1,n,x,y)); if(z==4)printf("%d ",Query2(1,1,n,x,y)); } } return 0; }
以上是关于HDU 3397 Sequence operation 多标记线段树的主要内容,如果未能解决你的问题,请参考以下文章
hdu-3397 Sequence operation 线段树多种标记
hdu 3397 Sequence operation (线段树 区间合并 多重标记)
HDU 3397 Sequence operation 多标记线段树