HDU - 3308 LCIS 题解
LCIS
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8225 Accepted Submission(s): 3524
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, indicating the case number.
Each case starts with two integers n , m(0<n,m<=105).
The next line has n integers(0<=val<=105).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=105)
OR
Q A B(0<=A<=B< n).
Output
For each Q, output the answer.
Sample Input
1
10 10
7 7 3 3 5 9 9 8 1 8
Q 6 6
U 3 4
Q 0 1
Q 0 5
Q 4 7
Q 3 5
Q 0 2
Q 4 6
U 6 10
Q 0 9
Sample Output
1
1
4
2
3
1
2
5
Author
shǎ崽
Source
HDOJ Monthly Contest – 2010.02.06
题意:
两种操作,一种单点修改值,第二种查询区间最长连续上升子序列长度。
思路一:
用L[i]存储总体序列中以第i个位置结尾的LICS长度。用线段树维护这个L的区间最大值,更改i位置值的时候他会影响到L[i],以及i以后的一段区间,这段区间是连续上升的,我们可以二分求出这段区间,然后再线段树区间更改他。查询的时候需要特殊考虑查询区间的最长上升前缀,再线段树查询剩的区间的L最大值,复杂度m*(logn)^2。
1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <cmath> 7 #include <string> 8 #include <cstring> 9 #include <algorithm> 10 #include <queue> 11 #include <stack> 12 #include <vector> 13 #include <set> 14 #include <map> 15 #include <list> 16 #include <iomanip> 17 #include <cctype> 18 #include <cassert> 19 #include <bitset> 20 #include <ctime> 21 22 using namespace std; 23 24 #define pau system("pause") 25 #define ll long long 26 #define pii pair<int, int> 27 #define pb push_back 28 #define mp make_pair 29 #define clr(a, x) memset(a, x, sizeof(a)) 30 31 const double pi = acos(-1.0); 32 const int INF = 0x3f3f3f3f; 33 const int MOD = 1e9 + 7; 34 const double EPS = 1e-9; 35 36 /* 37 #include <ext/pb_ds/assoc_container.hpp> 38 #include <ext/pb_ds/tree_policy.hpp> 39 40 using namespace __gnu_pbds; 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T; 42 */ 43 44 int t, n, m, val[100015], L[100015]; 45 int Ma[400015], lazy[400015]; 46 void pushup(int i) { 47 Ma[i] = max(Ma[i << 1], Ma[i << 1 | 1]); 48 } 49 void pushdown(int i) { 50 if (lazy[i]) { 51 Ma[i << 1] += lazy[i]; 52 Ma[i << 1 | 1] += lazy[i]; 53 lazy[i << 1] += lazy[i]; 54 lazy[i << 1 | 1] += lazy[i]; 55 lazy[i] = 0; 56 } 57 } 58 void build(int i, int l, int r) { 59 lazy[i] = 0; 60 if (l == r) { 61 Ma[i] = L[l]; 62 return; 63 } 64 int mi = l + r >> 1; 65 build(i << 1, l, mi); 66 build(i << 1 | 1, mi + 1, r); 67 pushup(i); 68 } 69 void update(int i, int l, int r, int x, int y, int z) { 70 if (x <= l && r <= y) { 71 Ma[i] += z; 72 lazy[i] += z; 73 return; 74 } 75 pushdown(i); 76 int mi = l + r >> 1; 77 if (x <= mi) update(i << 1, l, mi, x, y, z); 78 if (mi < y) update(i << 1 | 1, mi + 1, r, x, y, z); 79 pushup(i); 80 } 81 int query(int i, int l, int r, int x, int y) { 82 if (x <= l && r <= y) { 83 return Ma[i]; 84 } 85 pushdown(i); 86 int res1 = 0, res2 = 0, mi = l + r >> 1; 87 if (x <= mi) res1 = query(i << 1, l, mi, x, y); 88 if (mi < y) res2 = query(i << 1 | 1, mi + 1, r, x, y); 89 return max(res1, res2); 90 } 91 //#define local 92 int main() { 93 #ifdef local 94 freopen("data.in", "r", stdin); 95 freopen("data.out", "w", stdout); 96 #endif // local 97 scanf("%d", &t); 98 val[0] = -1, L[0] = 0; 99 while (t--) { 100 scanf("%d%d", &n, &m); 101 for (int i = 1; i <= n; ++i) { 102 scanf("%d", &val[i]); 103 if (val[i] > val[i - 1]) { 104 L[i] = L[i - 1] + 1; 105 } else { 106 L[i] = 1; 107 } 108 } 109 build(1, 1, n); 110 while (m--) { 111 char op; 112 int a, b; 113 scanf(" %c %d%d", &op, &a, &b); 114 if ('U' == op) { 115 ++a; 116 L[a] = query(1, 1, n, a, a); 117 int pre_l = L[a], pre_v = val[a]; 118 val[a] = b; 119 if (a > 1) { 120 L[a - 1] = query(1, 1, n, a - 1, a - 1); 121 } 122 L[a] = (val[a] > val[a - 1] ? L[a - 1] + 1 : 1); 123 update(1, 1, n, a, a, L[a] - pre_l); 124 if (a == n) continue; 125 int s = a + 1, e = n, mi, pos; 126 L[a + 1] = query(1, 1, n, a + 1, a + 1); 127 while (s <= e) { 128 mi = s + e >> 1; 129 L[mi] = query(1, 1, n, mi, mi); 130 if (L[mi] - L[a + 1] == mi - a - 1) { 131 s = (pos = mi) + 1; 132 } else { 133 e = mi - 1; 134 } 135 } 136 if (pre_v < val[a + 1] && val[a] >= val[a + 1]) { 137 update(1, 1, n, a + 1, pos, -pre_l); // pre_l换成 L[a] 不对 138 } else if (pre_v >= val[a + 1] && val[a] < val[a + 1]) { 139 update(1, 1, n, a + 1, pos, L[a]); 140 } else if (val[a] < val[a + 1]) { 141 update(1, 1, n, a + 1, pos, L[a] - pre_l); 142 } 143 } else { 144 ++a, ++b; 145 int s = a, e = b, mi, pos1 = b + 1, pos2 = a - 1; 146 L[a] = query(1, 1, n, a, a); 147 while (s <= e) { 148 mi = s + e >> 1; 149 L[mi] = query(1, 1, n, mi, mi); 150 if (mi - a == L[mi] - L[a]) { 151 s = mi + 1; 152 } else { 153 e = (pos1 = mi) - 1; 154 } 155 } 156 int ans = pos1 - a; 157 if (pos1 <= b) { 158 int res = query(1, 1, n, pos1, b); 159 ans = max(ans, res); 160 } 161 printf("%d\n", ans); 162 } 163 } 164 } 165 return 0; 166 } 167 /* 168 2 169 10 6 170 1 3 6 2 7 4 3 5 6 6 171 Q 0 9 172 U 2 1 173 Q 1 4 174 U 5 1 175 Q 2 8 176 Q 5 7 177 */
思路二:
刚学习到这是一类经典的线段树区间合并问题。线段树节点可以维护三个值,区间内最大连续子串,包含左端点的最大连续子串,包含右端点的最大连续子串,pushup向上维护父节点信息的时候都可以通过这三个值维护出来,同时对query函数做几乎一样的分类讨论处理就行了,复杂度mlogn。
1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <cmath> 7 #include <string> 8 #include <cstring> 9 #include <algorithm> 10 #include <queue> 11 #include <stack> 12 #include <vector> 13 #include <set> 14 #include <map> 15 #include <list> 16 #include <iomanip> 17 #include <cctype> 18 #include <cassert> 19 #include <bitset> 20 #include <ctime> 21 22 using namespace std; 23 24 #define pau system("pause") 25 #define ll long long 26 #define pii pair<int, int> 27 #define pb push_back 28 #define mp make_pair 29 #define clr(a, x) memset(a, x, sizeof(a)) 30 31 const double pi = acos(-1.0); 32 const int INF = 0x3f3f3f3f; 33 const int MOD = 1e9 + 7; 34 const double EPS = 1e-9; 35 36 /* 37 #include <ext/pb_ds/assoc_container.hpp> 38 #include <ext/pb_ds/tree_policy.hpp> 39 40 using namespace __gnu_pbds; 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T; 42 */ 43 44 int t, n, m, val[100015]; 45 struct node { 46 int Ma, Ma_l, Ma_r; 47 node () {} 48 node (int Ma, int Ma_l, int Ma_r) : Ma(Ma), Ma_l(Ma_l), Ma_r(Ma_r) {} 49 } Node[400015]; 50 void pushup(int i, int l, int r) { 51 int mi = l + r >> 1, lson = i << 1, rson = i << 1 | 1; 52 Node[i].Ma_l = Node[lson].Ma_l; 53 Node[i].Ma_r = Node[rson].Ma_r; 54 Node[i].Ma = max(Node[lson].Ma, Node[rson].Ma); 55 if (val[mi] < val[mi + 1]) { 56 if (Node[lson].Ma_l == mi - l + 1) { 57 Node[i].Ma_l = Node[lson].Ma_l + Node[rson].Ma_l; 58 } 59 if (Node[rson].Ma_r == r - mi) { 60 Node[i].Ma_r = Node[rson].Ma_r + Node[lson].Ma_r; 61 } 62 Node[i].Ma = max(Node[i].Ma, Node[lson].Ma_r + Node[rson].Ma_l); 63 } 64 } 65 void build(int i, int l, int r) { 66 if (l == r) { 67 Node[i] = node(1, 1, 1); 68 return; 69 } 70 int mi = l + r >> 1; 71 build(i << 1, l, mi); 72 build(i << 1 | 1, mi + 1, r); 73 pushup(i, l, r); 74 } 75 void update(int i, int l, int r, int p, int z) { 76 if (l == r) { 77 val[l] = z; 78 return; 79 } 80 int mi = l + r >> 1; 81 if (p <= mi) update(i << 1, l, mi, p, z); 82 if (mi < p) update(i << 1 | 1, mi + 1, r, p, z); 83 pushup(i, l, r); 84 } 85 node query(int i, int l, int r, int x, int y) { 86 if (x <= l && r <= y) { 87 return Node[i]; 88 } 89 int mi = l + r >> 1; 90 node ans, res1, res2; 91 ans = res1 = res2 = node(0, 0, 0); 92 if (x <= mi) res1 = query(i << 1, l, mi, x, y); 93 if (mi < y) res2 = query(i << 1 | 1, mi + 1, r, x, y); 94 ans.Ma = max(res1.Ma, res2.Ma); 95 ans.Ma_l = res1.Ma_l, ans.Ma_r = res2.Ma_r; 96 if (x <= mi && mi < y && val[mi] < val[mi + 1]) { 97 ans.Ma = max(ans.Ma, res1.Ma_r + res2.Ma_l); 98 if (res1.Ma_l == mi - l + 1) { 99 ans.Ma_l = res1.Ma_l + res2.Ma_l; 100 } 101 if (res2.Ma_r == r - mi) { 102 ans.Ma_r = res1.Ma_r + res2.Ma_r; 103 } 104 } 105 return ans; 106 } 107 void print() { 108 for (int i = 1; i <= n << 2; ++i) { 109 printf("Node[%d].Ma = %d, Ma_l = %d, Ma_r = %d ", i, Node[i].Ma, Node[i].Ma_l, Node[i].Ma_r); 110 if (i % 2 == 0) puts(""); 111 } 112 for (int i = 1; i <= n; ++i) printf("%d ", val[i]); 113 puts(""); 114 } 115 int main() { 116 scanf("%d", &t); 117 while (t--) { 118 scanf("%d%d", &n, &m); 119 for (int i = 1; i <= n; ++i) scanf("%d", &val[i]); 120 build(1, 1, n); 121 while (m--) { 122 char op; 123 int x, y; 124 scanf(" %c%d%d", &op, &x, &y); 125 if ('U' == op) { 126 update(1, 1, n, ++x, y); 127 } else { 128 printf("%d\n", query(1, 1, n, ++x, ++y).Ma); 129 } 130 } 131 } 132 return 0; 133 }
废话:最近的代码总坑在几处细微甚至不该错的地方,而且好久都调不出来,最近确实有些累了,状态不太好,更主要的还是练得不够呀...