POJ-3667 线段树区间合并入门题
Posted qaqorz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ-3667 线段树区间合并入门题相关的知识,希望对你有一定的参考价值。
题意:长度为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 "); 79 else { 80 b = query(1, n, 1, a); 81 printf("%d ", 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 线段树区间合并入门题的主要内容,如果未能解决你的问题,请参考以下文章