1. 程式人生 > >POJ-3667 線段樹區間合並入門題

POJ-3667 線段樹區間合並入門題

\n 向上 urn 開始 連續 每次 線段樹 最大連續 ()

題意:長度為n的區間,m個操作,一開始都是0

1 x表示求出長度為x的0的連續區間的最左端,並把這個區間變成1

2 x y表示將區間[x,y]變成0

線段樹的區間合並第一題:

每次維護左端連續區間長度ls、右端連續區間長度rs,最大連續長度ms

區間合並的註意點主要在push up操作:

每次更新了一段區間之後向上更新,首先,父區間的ls繼承左子樹的ls,父區間的rs繼承右子樹的rs

然後就是重點:左右區間合並之後中間部分可能是連續的!!!

所以:如果整個左、右子區間都是“滿的”,父區間的ls和rs分別就要連到另一側去

最後,父區間的ms要比較三個值:ls、rs和【左區間的rs加上右區間的ls】,這裏畫個圖或者聯系歸並排序就可以看出來

貼一下模板以後不手敲了,怕出錯

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define lid id << 1
 4 #define rid id << 1 | 1
 5 using namespace std;
 6 
 7 const int mx = 50010;
 8 
 9 struct tree{
10     int l, r;
11     int ls, rs, ms;
12     int lazy;
13 }tree[mx<<2];
14 15 void build(int l, int r, int id){ 16 tree[id].l = l; 17 tree[id].r = r; 18 tree[id].ls = tree[id].rs = tree[id].ms = r-l+1; 19 tree[id].lazy = -1; 20 if (l == r) return; 21 int mid = (l+r) >> 1; 22 build(l, mid, lid); 23 build(mid+1, r, rid); 24 }
25 26 void pushdown(int id){ 27 if (tree[id].lazy != -1){ 28 tree[lid].lazy = tree[rid].lazy = tree[id].lazy; 29 tree[lid].ls = tree[lid].rs = tree[lid].ms = tree[id].lazy ? 0 : tree[lid].r-tree[lid].l+1; 30 tree[rid].ls = tree[rid].rs = tree[rid].ms = tree[id].lazy ? 0 : tree[rid].r-tree[rid].l+1; 31 tree[id].lazy = -1; 32 } 33 } 34 35 void pushup(int id){ 36 tree[id].ls = tree[lid].ls; 37 tree[id].rs = tree[rid].rs; 38 int mid = (tree[id].l + tree[id].r) >> 1; 39 if (tree[id].ls == mid-tree[id].l+1) tree[id].ls += tree[rid].ls; 40 if (tree[id].rs == tree[id].r-mid) tree[id].rs += tree[lid].rs; 41 tree[id].ms = max(max(tree[lid].ms, tree[rid].ms), tree[lid].rs+tree[rid].ls); 42 } 43 44 void upd(int l, int r, int id, bool x){ 45 if (tree[id].l == l && tree[id].r == r){ 46 tree[id].lazy = x; 47 tree[id].ls = tree[id].rs = tree[id].ms = x ? 0 : r-l+1; 48 return; 49 } 50 pushdown(id); 51 int mid = (tree[id].l + tree[id].r) >> 1; 52 if (r <= mid) upd(l, r, lid, x); 53 else if (mid < l) upd(l, r, rid, x); 54 else { 55 upd(l, mid, lid, x); 56 upd(mid+1, r, rid, x); 57 } 58 pushup(id); 59 } 60 61 int query(int l, int r, int id, int x){ 62 if (l == r) return l; 63 pushdown(id); 64 int mid = (l+r) >> 1; 65 if (tree[lid].ms >= x) return query(l, mid, lid, x); 66 else if (tree[lid].rs + tree[rid].ls >= x) return mid-tree[lid].rs+1; 67 return query(mid+1, r, rid, x); 68 } 69 70 int main(){ 71 int n, m; 72 scanf("%d%d", &n, &m); 73 build(1, n, 1); 74 while (m--){ 75 int op, a, b; 76 scanf("%d%d", &op, &a); 77 if (op == 1){ 78 if (tree[1].ms < a) printf("0\n"); 79 else { 80 b = query(1, n, 1, a); 81 printf("%d\n", b); 82 upd(b, b+a-1, 1, 1); 83 } 84 } 85 else { 86 scanf("%d", &b); 87 upd(a, a+b-1, 1, 0); 88 } 89 } 90 return 0; 91 }

POJ-3667 線段樹區間合並入門題