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<=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
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;
}