hdu 3379 Sequence operation(成段更新,區間合併)
阿新 • • 發佈:2019-01-23
線段樹很好的題。涉及到的知識點:lazy操作處理異或操作和置01,區間合併。
有五種操作:
0 a b 將[a,b]變為0
1 a b 將[a,b]變為1
2 a b 將[a,b]取反
3 a b 輸出[a,b]的1的個數
4 a b 輸出[a,b]內最長的連續1的個數
對區間的操作與poj 3225類似。置01與取反是互斥的,一段區間上只能有一個標記,discuss裡面也說了取反的時候若遞迴到區間全為0或1的時候再取反違背了線段樹的本質。因此對於這兩個操作設定一個變數lazy,它的取值有-1,0,1,2,-1表示沒有操作,0和1表示被0或1覆蓋,2表示區間取反。因為兩次取反後相當於沒取,lazy標記在這裡起到很大作用,若要對這個區間取反,只需將其lazy置為2,下次再取反時就變為原來的,即置為-1。
詢問區間的1的個數時,只需要sum維護區間的和即可。求連續的1的長度時,需要區間合併,又因為有取反操作,同時還要記錄區間內連續的0的個數。
#include <stdio.h> #include <iostream> #include <map> #include <set> #include <list> #include <stack> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #include <stdlib.h> #include <algorithm> //#define LL long long #define LL __int64 #define eps 1e-12 #define PI acos(-1.0) using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 100010; /* 節點共有如下資訊: lazy:標記區間中的操作或覆蓋情況, sum:區間的和, ll[2]表示從左邊數連續的0和1的個數,rr[2]表示從右邊數連續的0和1的個數, long0、long1分別表示最長的連續的0和1的長度。 */ struct node { int l,r; int lazy; int sum; int ll[2],rr[2]; int long1,long0; }tree[maxn*4]; int a[maxn]; /* 向上更新,更新父親節點的和以及ll[],rr[],long0,long1 */ void push_up(int v) { int l = tree[v].l,r = tree[v].r; int ls = v*2,rs = v*2+1; int mid = (l+r)>>1; tree[v].sum = tree[ls].sum + tree[rs].sum; tree[v].ll[0] = tree[ls].ll[0]; if(tree[ls].sum == 0) tree[v].ll[0] += tree[rs].ll[0]; tree[v].ll[1] = tree[ls].ll[1]; if(tree[ls].sum == mid-l+1) tree[v].ll[1] += tree[rs].ll[1]; tree[v].rr[0] = tree[rs].rr[0]; if(tree[rs].sum == 0) tree[v].rr[0] += tree[ls].rr[0]; tree[v].rr[1] = tree[rs].rr[1]; if(tree[rs].sum == r-mid) tree[v].rr[1] += tree[ls].rr[1]; tree[v].long0 = max(max(tree[ls].long0,tree[rs].long0),tree[ls].rr[0]+tree[rs].ll[0]); tree[v].long1 = max(max(tree[ls].long1,tree[rs].long1),tree[ls].rr[1]+tree[rs].ll[1]); } /* 向下更新,lazy為0或1時直接覆蓋子區間,為2時看子區間是否被完全覆蓋,若是就直接取反,否則子節點的lazy取反 */ void push_down(int v) { if(tree[v].l == tree[v].r || tree[v].lazy == -1) return; int l = tree[v].l,r = tree[v].r; int ls = v*2,rs = v*2+1; int mid = (l + r)>>1; if(tree[v].lazy == 0) { tree[ls].lazy = tree[rs].lazy = 0; tree[ls].sum = tree[rs].sum = 0; tree[ls].long1 = tree[rs].long1 = 0; tree[ls].ll[1] = tree[ls].rr[1] = tree[rs].ll[1] = tree[rs].rr[1] = 0; tree[ls].ll[0] = tree[ls].rr[0] = tree[ls].long0 = mid-l+1; tree[rs].ll[0] = tree[rs].rr[0] = tree[rs].long0 = r-mid; } else if(tree[v].lazy == 1) { tree[ls].lazy = tree[rs].lazy = 1; tree[ls].sum = mid-l+1; tree[rs].sum = r-mid; tree[ls].long0 = tree[rs].long0 = 0; tree[ls].ll[0] = tree[ls].rr[0] = tree[rs].ll[0] = tree[rs].rr[0] = 0; tree[ls].ll[1] = tree[ls].rr[1] = tree[ls].long1 = mid-l+1; tree[rs].ll[1] = tree[rs].rr[1] = tree[rs].long1 = r-mid; } else if(tree[v].lazy == 2) { if(tree[ls].lazy == -1 || tree[ls].lazy == 2) { tree[ls].lazy = 1-tree[ls].lazy; tree[ls].sum = mid-l+1-tree[ls].sum; swap(tree[ls].long0,tree[ls].long1); swap(tree[ls].ll[0],tree[ls].ll[1]); swap(tree[ls].rr[0],tree[ls].rr[1]); } else if(tree[ls].lazy == 1) { tree[ls].lazy = 0; tree[ls].sum = 0; tree[ls].long0 = tree[ls].ll[0] = tree[ls].rr[0] = mid-l+1; tree[ls].long1 = tree[ls].ll[1] = tree[ls].rr[1] = 0; } else if(tree[ls].lazy == 0) { tree[ls].lazy = 1; tree[ls].sum = mid-l+1; tree[ls].long0 = tree[ls].ll[0] = tree[ls].rr[0] = 0; tree[ls].long1 = tree[ls].ll[1] = tree[ls].rr[1] = mid-l+1; } if(tree[rs].lazy == -1 || tree[rs].lazy == 2) { tree[rs].lazy = 1-tree[rs].lazy; tree[rs].sum = r-mid-tree[rs].sum; swap(tree[rs].long0,tree[rs].long1); swap(tree[rs].ll[0],tree[rs].ll[1]); swap(tree[rs].rr[0],tree[rs].rr[1]); } else if(tree[rs].lazy == 1) { tree[rs].lazy = 0; tree[rs].sum = 0; tree[rs].long0 = tree[rs].ll[0] = tree[rs].rr[0] = r-mid; tree[rs].long1 = tree[rs].ll[1] = tree[rs].rr[1] = 0; } else if(tree[rs].lazy == 0) { tree[rs].lazy = 1; tree[rs].sum = r-mid; tree[rs].long0 = tree[rs].ll[0] = tree[rs].rr[0] = 0; tree[rs].long1 = tree[rs].ll[1] = tree[rs].rr[1] = r-mid; } } tree[v].lazy = -1; } void build(int v, int l, int r) { tree[v].l = l; tree[v].r = r; tree[v].lazy = -1; tree[v].sum = 0; tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = 0; tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = 0; if(l == r) { tree[v].sum = a[l]; if(a[l] == 0) tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = 1; else tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = 1; return; } int mid = (l+r)>>1; build(v*2,l,mid); build(v*2+1,mid+1,r); push_up(v); } void update(int v, int l, int r, int op) { if(tree[v].l == l && tree[v].r == r) { if(op == 0) { tree[v].lazy = tree[v].sum = 0; tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = tree[v].r - tree[v].l + 1; tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = 0; } else if(op == 1) { tree[v].lazy = 1; tree[v].sum = tree[v].r - tree[v].l + 1; tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = tree[v].r - tree[v].l + 1; tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = 0; } else if(op == 2) { if(tree[v].lazy == 0) { tree[v].lazy = 1; tree[v].sum = tree[v].r - tree[v].l + 1; tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = tree[v].r-tree[v].l+1; tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = 0; } else if(tree[v].lazy == 1) { tree[v].lazy = tree[v].sum = 0; tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = 0; tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = tree[v].r-tree[v].l+1; } else if(tree[v].lazy == -1 || tree[v].lazy == 2) { tree[v].lazy = 1-tree[v].lazy; tree[v].sum = tree[v].r-tree[v].l+1-tree[v].sum; swap(tree[v].long0,tree[v].long1); swap(tree[v].ll[0],tree[v].ll[1]); swap(tree[v].rr[0],tree[v].rr[1]); } } return; } push_down(v); int mid = (tree[v].l + tree[v].r) >> 1; if(r <= mid) update(v*2,l,r,op); else if(l > mid) update(v*2+1,l,r,op); else { update(v*2,l,mid,op); update(v*2+1,mid+1,r,op); } push_up(v); } int query(int v, int l, int r,int op) { if(tree[v].l == l && tree[v].r == r) { if(op == 3) return tree[v].sum; else return tree[v].long1; } push_down(v); int mid = (tree[v].l + tree[v].r) >> 1; if(r <= mid) return query(v*2,l,r,op); else if(l > mid) return query(v*2+1,l,r,op); else { if(op == 3) return query(v*2,l,mid,op) + query(v*2+1,mid+1,r,op); else { //求區間[l,r]中最長的連續是1的長度。 int tmp = min(tree[v*2].rr[1],mid-l+1) + min(tree[v*2+1].ll[1],r-mid); return max(tmp,max(query(v*2,l,mid,op),query(v*2+1,mid+1,r,op))); } } } int main() { int test; int n,m; int op,l,r; scanf("%d",&test); while(test--) { scanf("%d %d",&n,&m); for(int i = 1; i <= n; i++) scanf("%d",&a[i]); build(1,1,n); while(m--) { scanf("%d %d %d",&op,&l,&r); l++; r++; if(op <= 2) { update(1,l,r,op); } else { int ans = query(1,l,r,op); printf("%d\n",ans); } } } return 0; }