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

Posted tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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,内部ls,rs为左右儿子的下标。l,r记录当前区间分别从左起和右起的LICS长度,s记录整个区间内的LICS长度。

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

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

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

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <iomanip>
  4 #include <cstring>
  5 #include <climits>
  6 #include <complex>
  7 #include <cassert>
  8 #include <cstdio>
  9 #include <bitset>
 10 #include <vector>
 11 #include <deque>
 12 #include <queue>
 13 #include <stack>
 14 #include <ctime>
 15 #include <set>
 16 #include <map>
 17 #include <cmath>
 18 using namespace std;
 19 
 20 #define lrt rt << 1
 21 #define rrt rt << 1 | 1
 22 const int maxn = 100050;
 23 typedef struct Node {
 24     int ls, rs;
 25     int s, l, r;
 26 }Node;
 27 
 28 Node seg[maxn<<2];
 29 int n, q;
 30 int seq[maxn];
 31 char cmd[3];
 32 
 33 
 34 void pushUP(int rt, int len) {
 35     seg[rt].l = seg[lrt].l;
 36     seg[rt].r = seg[rrt].r;
 37     if(seg[rt].l == len-len/2) {
 38         if(seq[seg[lrt].rs] < seq[seg[rrt].ls]) {
 39             seg[rt].l += seg[rrt].l;
 40         }
 41     }
 42     if(seg[rt].r == len/2) {
 43         if(seq[seg[lrt].rs] < seq[seg[rrt].ls]) {
 44             seg[rt].r += seg[lrt].r;
 45         }
 46     }
 47     seg[rt].s = max(seg[lrt].s, seg[rrt].s);
 48     if(seq[seg[lrt].rs] < seq[seg[rrt].ls]) {
 49         seg[rt].s = max(seg[rt].s, seg[lrt].r+seg[rrt].l);
 50     }
 51 }
 52 
 53 void build(int l, int r, int rt) {
 54     seg[rt].ls = l;
 55     seg[rt].rs = r;
 56     if(l == r) {
 57         seg[rt].l = seg[rt].r = seg[rt].s = 1;
 58         return;
 59     }
 60     int mid = (l + r) >> 1;
 61     build(l, mid, lrt);
 62     build(mid+1, r, rrt);
 63     pushUP(rt, seg[rt].rs-seg[rt].ls+1);
 64 }
 65 
 66 int query(int L, int R, int rt) {
 67     if(L <= seg[rt].ls && seg[rt].rs <= R) return seg[rt].s;
 68     int mid = (seg[rt].ls + seg[rt].rs) >> 1;
 69     if(mid >= R) return query(L, R, lrt);
 70     else if(mid + 1 <= L) return query(L, R, rrt);
 71     else {
 72         int tmp = max(query(L, mid, lrt), query(mid+1, R, rrt));
 73         if(seq[seg[lrt].rs] < seq[seg[rrt].ls]) {
 74             tmp = max(tmp, min(seg[lrt].r,mid-L+1)+min(seg[rrt].l,R-mid));
 75         }
 76         return tmp;
 77     }
 78 }
 79 
 80 void update(int L, int R, int rt) {
 81     if(L <= seg[rt].ls && seg[rt].rs <= R) {
 82         seg[rt].l = seg[rt].r = seg[rt].s = 1;
 83         return;
 84     }
 85     int mid = (seg[rt].ls + seg[rt].rs) >> 1;
 86     if(mid >= L) update(L, R, lrt);
 87     if(mid < R) update(L, R, rrt);
 88     pushUP(rt, seg[rt].rs-seg[rt].ls+1);
 89 }
 90 
 91 int main() {
 92     // freopen("in", "r", stdin);
 93     int qaq, a, b;
 94     scanf("%d", &qaq);
 95     while(qaq--) {
 96         scanf("%d %d", &n, &q);
 97         for(int i = 1; i <= n; i++) {
 98             scanf("%d", &seq[i]);
 99         }
100         build(1, n, 1);
101         while(q--) {
102             scanf("%s %d %d",cmd,&a,&b);
103             a++;
104             if(cmd[0] == Q) {
105                 b++;
106                 printf("%d\n", query(a, b, 1));
107             }
108             else if(cmd[0] == U) {
109                 seq[a] = b;
110                 update(a, a, 1);
111             }
112         }
113     }
114     return 0;
115 }

 

以上是关于[HDOJ3308]LCIS(线段树,区间合并)的主要内容,如果未能解决你的问题,请参考以下文章

[HDOJ3308]LCIS(线段树,区间合并,新的代码)

HDU 3308 LCIS (线段树区间合并)

HDU 3308 LCIS (经典区间合并)线段树

hdu--3308 LCIS(线段树+区间合并)

hdu 3308 LCIS(线段树区间合并)

hdu 3308 LCIS(线段树)