HDU 3308(LCIS)

题意:动态修改查询区间最长连续上升序列,注意:是连续的。

思路:线段树区间合并的经典题,做这题最重要的是要写好pushUp函数,写pushUp函数需要递推一下,题目是求连续最长的子序列,所以可以知道每个区间的最长子序列有三种情况:1.最长子序列在左子区间;2.最长子序列在右子区间;3.最长子序列由左子区间和右子区间组成;前面两种情况直接更新到上一层即可,第三种情况则需将左子区间和右子区间合并,每个结点开辟两个变量L,R(记录长度); L记录以本区间第一个元素开始的最长连续上升子序列,R记录以本区间最右元素结束的最长上升子序列,然后合并的时候比较一下看是否需要更新就可以了;

另外,在询问的时候,也需要将左右两个子区间合并,看是否有最大值。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 100010;
int T, n, q, num[N], res;
struct segTree{
	int lc, rc, maxLen, R, L;
}arr[N * 4];
inline int lson(int idx){
	return (idx << 1);
}
inline int rson(int idx){
	return ((idx << 1) | 1);	
}

void pushUp(int idx){
	arr[idx].maxLen = max(arr[lson(idx)].maxLen, arr[rson(idx)].maxLen);
	arr[idx].R = arr[rson(idx)].R;
	arr[idx].L = arr[lson(idx)].L;
	if(num[arr[rson(idx)].lc] > num[arr[lson(idx)].rc]){
		arr[idx].maxLen = max(arr[idx].maxLen, arr[lson(idx)].R + arr[rson(idx)].L);
		if(arr[rson(idx)].R == arr[rson(idx)].rc - arr[rson(idx)].lc + 1)
			arr[idx].R = arr[lson(idx)].R + arr[rson(idx)].R;
		if(arr[lson(idx)].L == arr[lson(idx)].rc - arr[lson(idx)].lc + 1)
			arr[idx].L = arr[lson(idx)].L + arr[rson(idx)].L;
	}
}

void build(int idx, int l, int r){
	arr[idx].lc = l, arr[idx].rc = r;
	if(l == r){
		arr[idx].maxLen = 1, arr[idx].R = 1, arr[idx].L = 1;
		return ;
	}
	int mid = (l + r) >> 1;
	build(lson(idx), l, mid);
	build(rson(idx), mid + 1, r);
	pushUp(idx);	
}

void update(int idx, int loc){
	if(arr[idx].lc > loc || loc > arr[idx].rc)
		return ;
	if(arr[idx].lc == arr[idx].rc)
		return;
	update(lson(idx), loc);
	update(rson(idx), loc);
	pushUp(idx);
}

void query(int idx, int l, int r){
	if(arr[idx].lc > r || l > arr[idx].rc)
		return ;
	if(arr[idx].lc >= l && arr[idx].rc <= r){
		res = max(res, arr[idx].maxLen);
		return ;
	}
	query(lson(idx), l, r);
	query(rson(idx), l, r);
	if(num[arr[rson(idx)].lc] > num[arr[lson(idx)].rc]){
		int x, y;
		if(arr[lson(idx)].rc - arr[lson(idx)].R < l)
			x = arr[lson(idx)].rc - l + 1;
		else
			x = arr[lson(idx)].R;
		if(arr[rson(idx)].lc + arr[rson(idx)].L > r)
			y = r - arr[rson(idx)].lc + 1;
		else
			y = arr[rson(idx)].L;
		res = max(res, x + y); 
	}
}

int main(){
	cin >> T;
	while(T--){
		int i;
		cin >> n >> q;
		for(i = 1;i <= n;i++)
			scanf("%d", &num[i]);
		build(1, 1, n);
		while(q--){
			int l, r;
			char ord[5];
			scanf("%s%d%d", ord, &l, &r);
			l++, r++;
			if(ord[0] == 'Q'){
				res = 1;
				query(1, l, r);
				printf("%d\n", res);
			}else{
				r--;
				num[l] = r;
				update(1, l);
			}
		}		
	}	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值