题目传送:LCIS
线段树,区间合并,一次过啦,没有纠结,这几天过的最愉快的一个题
思路:求最长连续上升子序列,外带单点更新,经典的线段树题目。具体看代码注释
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <deque>
#include <cctype>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int n, m;
const int maxn = 100005;
struct node {
int sub;//表示当前结点最长连续上升子序列
int lsub;//表示以最左边为开始的最长连续上升子序列
int rsub;//表示以最右边为结束的最长连续上升子序列
int l, r;//表示当前结点(一段区间)的最左位置的值和最右位置的值
}e[maxn << 2];
void pushup(int rt, int m) {//往上更新,略复杂
e[rt].l = e[rt << 1].l;//更新最左
e[rt].r = e[rt << 1 | 1].r;//更新最右
e[rt].sub = max(e[rt << 1].sub, e[rt << 1 | 1].sub);//更新当前结点最长连续上升子序列
if(e[rt << 1 | 1].l > e[rt << 1].r)
e[rt].sub = max(e[rt].sub, e[rt << 1].rsub + e[rt << 1 | 1].lsub);
e[rt].lsub = e[rt << 1].lsub;//更新以最左边为开始的最长连续上升子序列
if(e[rt].lsub == m - (m >> 1) && e[rt << 1].r < e[rt << 1 | 1].l)
e[rt].lsub += e[rt << 1 | 1].lsub;
e[rt].rsub = e[rt << 1 | 1].rsub;//更新以最右边为结束的最长连续上升子序列
if(e[rt].rsub == (m >> 1) && e[rt << 1].r < e[rt << 1 | 1].l)
e[rt].rsub += e[rt << 1].rsub;
}
void build(int l, int r, int rt) {//建树
if(l == r) {
int t;
scanf("%d", &t);
e[rt].l = e[rt].r = t;
e[rt].sub = e[rt].lsub = e[rt].rsub = 1;
return;
}
int mid = (l + r) >> 1;
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
pushup(rt, r - l + 1);
}
int query(int L, int R, int l, int r, int rt) {//查询
if(L <= l && r <= R) {
return e[rt].sub;
}
int ret = 0;
int mid = (l + r) >> 1;
if(L <= mid) ret = max(ret, query(L, R, l, mid, rt << 1));
if(mid < R) ret = max(ret, query(L, R, mid + 1, r, rt << 1 | 1));
if(e[rt << 1].r < e[rt << 1 | 1].l && mid >= L && mid < R)//关键,看是否取中间的连续上升子序列
ret = max(ret, min(e[rt << 1].rsub, mid - L + 1) + min(e[rt << 1 | 1].lsub, R - mid));
return ret;
}
void update(int p, int x, int l, int r, int rt) {//更新
if(l == r) {
e[rt].l = e[rt].r = x;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) update(p, x, l, mid, rt << 1);
else update(p, x, mid + 1, r, rt << 1 | 1);
pushup(rt, r - l + 1);
}
int main() {
int T;
scanf("%d", &T);
while(T --) {
scanf("%d %d", &n, &m);
build(0, n - 1, 1);
char op[5];
int a, b;
while(m --) {
scanf("%s %d %d", op, &a, &b);
if(op[0] == 'Q') {
printf("%d\n", query(a, b, 0, n - 1, 1));
}
else if(op[0] == 'U') {
update(a, b, 0, n - 1, 1);
}
}
}
return 0;
}