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

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

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

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

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

我认为当时的代码风格和现在的不一样(因为喜欢在Seg里存l和r的下标,然而根本不用),所以重写了一份,也算是复习了。

pushup操作里是不需要根据seg[rt].ls和seg[rt].rs更新seg[rt].ms的,而是从左右儿子的ms更新,以及lrt的最右元素与rrt的最左元素满足上升关系时,将这lrt的rs和rrt的ls连起来。

query的时候也会遇到合并的问题,所以要像pushup操作一样,把两部分加起来更新一下结果。

query里除了判断上升关系,L <= mid && mid < 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 Seg {
 7     int ls, rs, ms;
 8 }Seg;
 9 const int maxn = 100100;
10 Seg seg[maxn<<2];
11 int val[maxn];
12 int n, q;
13 char op[3];
14
15 void pushup(int l, int r, int rt) {
16     int mid = (l + r) >> 1;
17     seg[rt].ls = seg[lrt].ls; seg[rt].rs = seg[rrt].rs;
18     if(seg[rt].ls == mid - l + 1 && val[mid] < val[mid+1]) seg[rt].ls += seg[rrt].ls;
19     if(seg[rt].rs == r - mid && val[mid] < val[mid+1]) seg[rt].rs += seg[lrt].rs;
20     seg[rt].ms = max(seg[lrt].ms, seg[rrt].ms);
21     if(val[mid] < val[mid+1]) seg[rt].ms = max(seg[rt].ms, seg[lrt].rs+seg[rrt].ls);
22 }
23
24 void build(int l, int r, int rt) {
25     if(l == r) {
26         seg[rt].ls = seg[rt].rs = seg[rt].ms = 1;
27         return;
28     }
29     int mid = (l + r) >> 1;
30     build(l, mid, lrt);
31     build(mid+1, r, rrt);
32     pushup(l, r, rt);
33 }
34
35 void update(int pos, int val, int l, int r, int rt) {
36     if(l == r) {
37         seg[rt].ls = seg[rt].rs = seg[rt].ms = 1;
38         return;
39     }
40     int mid = (l + r) >> 1;
41     if(pos <= mid) update(pos, val, l, mid, lrt);
42     else update(pos, val, mid+1, r, rrt);
43     pushup(l, r, rt);
44 }
45
46 int query(int L, int R, int l, int r, int rt) {
47     if(L <= l && r <= R) return seg[rt].ms;
48     int mid = (l + r) >> 1;
49     int ret = 0;
50     if(L <= mid) ret = max(ret, query(L, R, l, mid, lrt));
51     if(mid < R) ret = max(ret, query(L, R, mid+1, r, rrt));
52     if(L <= mid && mid < R && val[mid] < val[mid+1]) {
53         ret = max(ret, min(seg[lrt].rs, mid-L+1)+min(seg[rrt].ls,R-mid));
54     }
55     return ret;
56 }
57 int main() {
58     // freopen("in", "r", stdin);
59     int T, a, b;
60     scanf("%d", &T);
61     while(T--) {
62         scanf("%d%d",&n,&q);
63         for(int i = 1; i <= n; i++) {
64             scanf("%d", &val[i]);
65         }
66         build(1, n, 1);
67         while(q--) {
68             scanf("%s%d%d",op,&a,&b);
69             a++;
70             if(op[0] == ‘Q‘) {
71                 b++;
72                 printf("%d\n", query(a, b, 1, n, 1));
73             }
74             else {
75                 val[a] = b;
76                 update(a, b, 1, n, 1);
77             }
78         }
79     }
80     return 0;
81 }
时间: 2024-10-10 16:38:00

[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