LCISTime Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5606 Accepted Submission(s): 2447
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<=10 5). The next line has n integers(0<=val<=10 5). The next m lines each has an operation: U A B(0<=A,n , 0<=B=10 5) OR Q A B(0<=A<=B< n).
Output
For each Q, output the answer.
Sample Input
Sample Output
|
题意:给你n个数组成的序列(序列中编号从0到n-1),有q次操作。
操作1——Q a b,让你输出区间[a, b]里面最长的连续递增序列的长度;
操作2——U a b,修改序列第a个数为b。
线段树单点更新 + 区间合并,重在PushUp函数的操作 和 查询操作。
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #define MAXN 100000+10 #define lson o<<1, l, mid #define rson o<<1|1, mid+1, r #define ll o<<1 #define rr o<<1|1 using namespace std; struct Tree { int l, r, len;//区间左右端点 和 长度 int lv, rv;//区间左端点的值 右端点的值 int lsum, rsum;//以区间左端点为起点的最长递增序列长度 以区间右端点为终点的最长递增序列长度 int sum;//区间 最长递增序列长度 }; Tree tree[MAXN<<2]; void PushUp(int o) { tree[o].lv = tree[ll].lv;//左子树的左端点值 tree[o].rv = tree[rr].rv;//右子树的右端点值 tree[o].lsum = tree[ll].lsum; tree[o].rsum = tree[rr].rsum; tree[o].sum = max(tree[ll].sum, tree[rr].sum); if(tree[ll].rv < tree[rr].lv) { if(tree[ll].lsum == tree[ll].len)//左半区间完全容纳最长递增序列 向右延伸 tree[o].lsum += tree[rr].lsum; if(tree[rr].rsum == tree[rr].len)//右半区间完全容纳最长递增序列 向左延伸 tree[o].rsum += tree[ll].rsum; //更新 左子树的右端点连续长度 + 右子树的左端点的连续长度 tree[o].sum = max(tree[o].sum, tree[ll].rsum + tree[rr].lsum);//更新最值 } } int a; void build(int o, int l, int r)//建树 { tree[o].l = l, tree[o].r = r; tree[o].len = r -l + 1; if(l == r) { scanf("%d", &a); tree[o].lv = tree[o].rv = a; tree[o].lsum = tree[o].rsum = tree[o].sum = 1; return ; } int mid = (l + r) >> 1; build(lson); build(rson); PushUp(o); } int query(int o, int L, int R) { if(L <= tree[o].l && R >= tree[o].r) return tree[o].sum; int mid = (tree[o].l + tree[o].r) >> 1; int ans = 0; if(L <= mid)//更新左子树 ans = max(ans, query(ll, L, R)); if(R > mid)//更新右子树 ans = max(ans, query(rr, L, R)); if(tree[ll].rv < tree[rr].lv)//更新最大值 注意要取最小段 不能超过要查询的区间 ans = max(ans, min(mid-L+1, tree[ll].rsum) + min(R-mid, tree[rr].lsum)); return ans; } void update(int o, int pos, int val) { if(tree[o].l == tree[o].r)//修改 { tree[o].lv = tree[o].rv = val; return ; } int mid = (tree[o].l + tree[o].r) >> 1; if(pos <= mid) update(ll, pos, val); else update(rr, pos, val); PushUp(o);//维护 上传 } int main() { int t; int n, q; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &q); build(1, 0, n-1);//建树 char str[5]; int a, b; while(q--) { scanf("%s%d%d", str, &a, &b); if(str[0] == 'Q') printf("%d\n", query(1, a, b)); else update(1, a, b); } } return 0; }