1. 程式人生 > >HDU 3397 Sequence operation 多標記線段樹

HDU 3397 Sequence operation 多標記線段樹

一個 name 原來 == opera cstring scan ostream 維護

/*
一開始維護了兩個標記 開了兩個數組
想的是 可能當前兩種操作都要做
但是太復雜了 不好處理
其實 當前要做的標記可以只有一個

我們在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\n",Query1(1,1,n,x,y)); if(z==4)printf("%d\n",Query2(1,1,n,x,y)); } } return 0; }

HDU 3397 Sequence operation 多標記線段樹