[HDOJ3308]LCIS(线段树,区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308

题意:给定n个数,两个操作:

U A B:将位置A的数值改成B

Q A B:查询[A,B]内最长连续上升子序列的长度。

注意到‘连续’一词,可以用线段树维护[L,R]区间内的LICS。

定义结构Node,内部l,r为左右儿子的下标。ls,rs记录当前区间分别从左起和右起的LICS长度,s记录整个区间内的LICS长度。

pushup:和一般的区间合并操作一样,但是要注意假如合并的左右子树中间有可能成为LICS的时候,要判断是否符合条件,即左起右边界和右起左边界是否满足严格的关系。

update:更新节点的时候直接赋值,再更新到线段树上的操作也是很常规的。

query:比较奇特,因为有左起右边界和右起左边界连接起来的情况,所以查询的时候不是缩小线段树规模,而是缩小查询规模来获得解。而且要注意[L,R]的边界问题。子树的范围未必恰好满足,可能会更长。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define lrt rt << 1
 5 #define rrt rt << 1 | 1
 6 typedef struct Node {
 7     int l, r;
 8     int ls, s, rs;
 9 }Node;
10 const int maxn = 100100;
11 char cmd[5];
12 int n, q;
13 int x[maxn];
14 Node seg[maxn<<4];
15 
16 void pushUP(int rt, int len) {
17   seg[rt].ls = seg[lrt].ls; seg[rt].rs = seg[rrt].rs;
18   if(seg[rt].ls == len-len/2) {
19     if(x[seg[lrt].r] < x[seg[rrt].l]) {
20       seg[rt].ls += seg[rrt].ls;
21     }
22   }
23   if(seg[rt].rs == len/2) {
24     if(x[seg[lrt].r] < x[seg[rrt].l]) {
25       seg[rt].rs += seg[lrt].rs;
26     }
27   }
28   seg[rt].s = max(seg[lrt].s, seg[rrt].s);
29   if(x[seg[lrt].r] < x[seg[rrt].l]) {
30     seg[rt].s = max(seg[rt].s, seg[lrt].rs+seg[rrt].ls);
31   }
32 }
33 
34 void build(int l, int r, int rt) {
35     seg[rt].l = l; seg[rt].r = r;
36     if(l == r) {
37     seg[rt].ls = seg[rt].rs = seg[rt].s = 1;
38     return;
39     }
40     int mid = (l + r) >> 1;
41   build(l, mid, lrt);
42   build(mid+1, r, rrt);
43   pushUP(rt, r-l+1);
44 }
45 
46 void update(int L, int R, int rt) {
47   if(L <= seg[rt].l && seg[rt].r <= R) {
48     seg[rt].ls = seg[rt].rs = seg[rt].s = 1;
49     return;
50   }
51   int mid = (seg[rt].l + seg[rt].r) >> 1;
52   if(L <= mid) update(L, R, lrt);
53   if(mid < R) update(L, R, rrt);
54   pushUP(rt, seg[rt].r-seg[rt].l+1);
55 }
56 
57 int query(int L, int R, int rt) {
58   if(L == seg[rt].l && R == seg[rt].r) return seg[rt].s;
59   int mid = (seg[rt].l + seg[rt].r) >> 1;
60   if(mid >= R) return query(L, R, lrt);
61   else if(mid + 1 <= L) return query(L, R, rrt);
62   else {
63     int tmp = max(query(L, mid, lrt), query(mid+1, R, rrt));
64     if(x[seg[lrt].r] < x[seg[rrt].l]) {
65       tmp = max(tmp, min(seg[lrt].rs, mid-L+1)+min(seg[rrt].ls, R-mid));
66     }
67     return tmp;
68   }
69 }
70 
71 int main() {
72 //    freopen("in", "r", stdin);
73     int T, a, b;
74     scanf("%d", &T);
75     while(T--) {
76         scanf("%d %d", &n, &q);
77         for(int i = 1; i <= n; i++) {
78             scanf("%d", &x[i]);
79         }
80         build(1, n, 1);
81         while(q--) {
82             scanf("%s %d %d", cmd, &a, &b);
83             a++;
84             if(cmd[0] == 'U') {
85                 x[a] = b;
86         update(a, a, 1);
87             }
88             else {
89                 b++;
90         printf("%d\n", query(a, b, 1));
91             }
92         }
93     }
94     return 0;
95 }

 

posted @ 2016-10-12 10:18  Kirai  阅读(195)  评论(0编辑  收藏  举报