HDU_1540_线段树区间连续维护

HDU 1540

  • 求包括该点在内左右边的连续长度
  • 线段树维护3个值.
    len:该点的区间中最大连续长度.
    leftlen:该点区间左端的最大连续长度
    rightlen:该点区间右端的最大连续长度

    线段树区间连续长度的维护:

  • 父节点的区间连续长度左子树区间长度、右子树区间长度、左子树右端+右子树左端的区间长度3着的中最大值
  • 父节点左端连续长度=左子树左端连续长度.如果左子树区间连续,那么还要加上右子树左端的区间连续长度
  • 同理.父节点右端连续长度=右子树右端连续长度.如果右子树区间连续,那么还要加上左子树的右端区间连续长度

查询某个点index的区间连续长度

  • 如果该点的区间恰好连续,或者区间连续长度=0,直接返回
  • 如果index左子树右端连续区间内,那么返回右端连续区间长度+右子树左端连续区间长度,不在就缩小范围去左子树继续递归找
  • indexmid右边也是同理.看代码把.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
const int maxn = 5e4+5;
int n,m;
int num[maxn];
struct segement {
int len, leftlen, rightlen;
#define len(x) tree[x].len
#define leftlen(x) tree[x].leftlen
#define rightlen(x) tree[x].rightlen
}tree[4*maxn];
void pushUp(int p,int left,int right) {
len(p) = max(len(2*p),len(2*p+1)); //左子树和右子树长度最大值
len(p) = max(len(p),rightlen(2*p)+leftlen(2*p+1)); // 或者是左子树右边连续+右子树左边连续
leftlen(p) = leftlen(2 * p); //父亲节点的最大左边长度是左子节点左边长度
rightlen(p) = rightlen(2 * p + 1);
int mid = (left + right)/2;
// 如果左子树是连续的,那么父节点左子树的值=左子树+右子树左端长度
if (leftlen(p) == mid - left + 1) leftlen(p) += leftlen(2*p+1);
if (rightlen(p) == right - mid) rightlen(p) += rightlen(2*p);
}
void build(int p,int left,int right) {
if (left == right) {
len(p) = leftlen(p) = rightlen(p) = 1;
return;
}
int mid = (left + right) / 2;
build(2*p,left,mid);
build(2*p+1,mid+1,right);
pushUp(p,left,right);
}
void update(int p,int left,int right,int index,int val) {
if (left == right && right == index) { //找到叶节点
len(p) = leftlen(p) = rightlen(p) = val;
return;
}
int mid = (left + right)/2;
if (index <= mid) update(2*p,left,mid,index,val);
else update(2*p+1,mid+1,right,index,val);
pushUp(p,left,right);
}
int query(int p,int left,int right,int index) {
if (len(p) == 0 || len(p) == right - left + 1) return len(p);
int mid = (left + right) / 2;
if (index <= mid)
// index不在左子树最右连续区间内,继续递归查找,反之同理
return index > mid - rightlen(2*p) ? rightlen(2*p) + leftlen(2*p+1) : query(2*p,left,mid,index);
return index <= mid + leftlen(2*p+1) ? leftlen(2*p+1) + rightlen(2*p) : query(2*p+1,mid+1,right,index);
}
int main() {
// freopen("a.txt", "r", stdin);
char ch[5];
int p;
while (scanf("%d%d",&n,&m) != EOF) {
stack<int> s;
build(1, 1, n);
while (m--) {
scanf("%s",ch);
if (ch[0] == 'R' && !s.empty()) {
p = s.top(); s.pop();
update(1,1,n,p,1);
} else if (ch[0] == 'D') {
scanf("%d",&p);
update(1, 1, n, p, 0);
s.push(p);
}
else {
scanf("%d",&p);
printf("%d\n",query(1,1,n,p));
}
}
}
return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!