题目链接
题意:一个序列,每次询问一个区间内最长连续上升子序列,或者修改一个位置的值
思路:线段树的区间合并,和最长连续子序列和是一样的思路,记录lsum, rsum, sum,表示左边连续长度,右边连续长度,和区间最长长度,然后pushup的时候进行区间合并操作即可
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define lson(x) ((x<<1)+1) #define rson(x) ((x<<1)+2) const int N = 100005; int t, n, m, a[N]; struct Node { int l, r, lsum, rsum, sum; int size() {return r - l + 1;} } node[N * 4]; void merge(Node &x, Node lson, Node rson) { x.l = lson.l; x.r = rson.r; x.lsum = lson.lsum; x.rsum = rson.rsum; x.sum = max(lson.sum, rson.sum); if (a[lson.r] < a[rson.l]) { if (lson.lsum == lson.size()) x.lsum = lson.lsum + rson.lsum; if (rson.rsum == rson.size()) x.rsum = lson.rsum + rson.rsum; x.sum = max(x.sum, lson.rsum + rson.lsum); } } void pushup(int x) { merge(node[x], node[lson(x)], node[rson(x)]); } void build(int l, int r, int x = 0) { node[x].l = l; node[x].r = r; if (l == r) { node[x].lsum = node[x].rsum = node[x].sum = 1; return; } int mid = (l + r) / 2; build(l, mid, lson(x)); build(mid + 1, r, rson(x)); pushup(x); } void add(int v, int val, int x = 0) { if (node[x].l == node[x].r) { a[node[x].l] = val; return; } int mid = (node[x].l + node[x].r) / 2; if (v <= mid) add(v, val, lson(x)); if (v > mid) add(v, val, rson(x)); pushup(x); } Node query(int l, int r, int x = 0) { if (node[x].l >= l && node[x].r <= r) return node[x]; int mid = (node[x].l + node[x].r) / 2; if (l <= mid && r > mid) { Node tmp; merge(tmp, query(l, r, lson(x)), query(l, r, rson(x))); return tmp; } else if (l <= mid) return query(l, r, lson(x)); else if (r > mid) return query(l, r, rson(x)); } int main() { scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); build(1, n); char op[2]; int x, y; while (m--) { scanf("%s%d%d", op, &x, &y); if (op[0] == 'U') add(x + 1, y); else printf("%d\n", query(x + 1, y + 1).sum); } } return 0; }