[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 }
时间: 2024-11-06 08:05:12

[HDOJ3308]LCIS(线段树,区间合并)的相关文章

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1

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

Problem Description Given n integers. You have two operations: U A B: replace the Ath number by B. (index counting from 0) Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b]. Input T in the first line, indicat

HDU 3308 LCIS(最长连续上升子序列)(线段树区间合并)

题意:给你n个整数,有两种操作,U A B把第A个数变成B,Q A B查询区间[A,B]的最长连续上升序列. 思路:还是查询和更新操作,而且也是询问区间中满足条件的连续最长区间 ,所以是线段树区间合并类型的题,通法是开三棵线段树,一个记录此区间内的LCIS的最长长度,一个记录从左边第一个数开始的LCIS长度,另一个记录从右边最后一个数结尾的LCIS长度.然后试图找到父亲与儿子关系维护的递推关系式就好 本题中的递推关系是: 1. 左儿子最右边的值 < 右儿子最左边的值 lmx = (左儿子的lmx

hdu 3308(线段树区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6069    Accepted Submission(s): 2635 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability

poj3667 线段树 区间合并

1 //Accepted 3728 KB 1079 ms 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a document

hdu3911 线段树 区间合并

1 //Accepted 3911 750MS 9872K 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a documen

线段树 区间合并

poj3667 Hotel 区间合并入门题,照着代码打的, 题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边       2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间,开三个数组,msum[rt]表示节点rt内连续的1的个数的最大值,lsum[rt]表示从节点rt左端点开始连续1的个数,rsum[rt]表示从节点rt右端点开始连续1的个数..线段树操作:update:区间替换 query:询问满足条件的最左端点 1 #include<iostream>

【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少.1 ≤ n ≤ 105,1 ≤ m ≤ 105,1 ≤ l ≤ r ≤ n, 1 ≤ k ≤ 20 Sample Input 9 9 -8 9 -1 -1 -1 9 -8 9 3 1 1 9 1 1 1 9 2 1 4 6 3 Sample Output 17 25