【链接】
http://acm.hdu.edu.cn/showproblem.php?pid=3308
【题意】
给你n个数,m个操作。
操作有两种:
1.U x y 将数组第x位变为y
2. Q x y 问数组第x位到第y位连续最长子序列的长度
【思路】
满足区间可加。
线段树维护信息:区间最长连续上升序列,前缀最长上升序列,后缀最长上升序列。
pushup(p)修改的时候注意判断条件
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 6;
int a[maxn];
struct node {
int l, r, sub, lc, rc;
}t[maxn<<2];
inline void pushup(int p) {//本题核心,pushup的修改
int mid = (t[p].l + t[p].r )>> 1;
t[p].lc = t[p << 1].lc; t[p].rc = t[p << 1 | 1].rc;
t[p].sub = max(t[p << 1].sub, t[p << 1 | 1].sub);
if (a[mid] < a[mid + 1]) {
if (t[p].lc == mid - t[p].l + 1)t[p].lc += t[p << 1 | 1].lc;
if (t[p].rc == t[p].r - mid)t[p].rc += t[p << 1].rc;
t[p].sub = max(t[p << 1].rc + t[p << 1 | 1].lc, t[p].sub);
}
}
void build(int p, int l, int r) {
t[p].l = l; t[p].r = r;
if (l == r) { t[p].lc = t[p].rc = t[p].sub = 1; return; }
int mid =( l + r )>> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
pushup(p);
}
void update(int p, int pos, int v) {//单点修改
if (t[p].l == t[p].r) {
return;
}
int mid = (t[p].l + t[p].r) >> 1;
if (pos <= mid)update(p << 1, pos, v);
else update(p << 1 | 1, pos, v);
pushup(p);
}
int query(int p, int l, int r) {//查询区间[t[p].l,t[p],r]的最长连续上升子序列,核心
if (l <= t[p].l&&r >= t[p].r) {
return t[p].sub;
}
int mid = (t[p].l + t[p].r) >> 1;
if (r <= mid)return query(p << 1, l, r);
if (l > mid)return query(p << 1 | 1, l, r);//一共三种可能:左区间,右区间或者横跨左右两个区间
int t1 = query(p << 1, l, r);
int t2 = query(p << 1 | 1, l, r);
int ans = max(t1, t2);
if (a[mid] < a[mid + 1]) {
ans = max(ans, min(t[p << 1].rc,mid-l+1) + min(t[p << 1 | 1].lc,r-mid));
}
return ans;
}
int main() {
int T;scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)scanf("%d", &a[i]);
build(1, 1, n);
while (m--) {
char op[5];
int x, y;
scanf("%s%d%d", op, &x, &y);x++;
if (op[0] == 'U') {
a[x] = y;
update(1, x, y);
}
else {
y++;
printf("%d\n", query(1, x, y));
}
}
}
scanf("%d", &T);
}