LCIS HDU - 3308 线段树区间合并

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

1
10 10
7 7 3 3 5 9 9 8 1 8 
Q 6 6
U 3 4
Q 0 1
Q 0 5
Q 4 7
Q 3 5
Q 0 2
Q 4 6
U 6 10
Q 0 9

Sample Output

1
1
4
2
3
1
2
5

题意:给你n个数,有m个操作:

U A B: 把第A个数换成B
Q A B: 求区间[A,B]中最长上升子序列

思路:求区间最长连续的1的变形,我们在合并两个区间时,左区间的右端点小于右区间的左端点时才合并。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+100;
int a[maxn];
struct node{
	int l,r; 
	int left,right,now;
}tree[maxn*4];
void pushup(int cur)
{
	tree[cur].now=max(tree[cur<<1].now,tree[cur<<1|1].now);
	tree[cur].left=tree[cur<<1].left;
	if(tree[cur<<1].left==tree[cur<<1].r-tree[cur<<1].l+1&&a[tree[cur<<1].r]<a[tree[cur<<1].r+1]) tree[cur].left+=tree[cur<<1|1].left;
	tree[cur].right=tree[cur<<1|1].right;
	if(tree[cur<<1|1].right==tree[cur<<1|1].r-tree[cur<<1|1].l+1&&a[tree[cur<<1].r]<a[tree[cur<<1].r+1]) tree[cur].right+=tree[cur<<1].right;
	if(a[tree[cur<<1].r]<a[tree[cur<<1].r+1]) tree[cur].now=max(tree[cur].now,tree[cur<<1].right+tree[cur<<1|1].left);
}
void build(int l,int r,int cur)
{
	tree[cur].l=l;
	tree[cur].r=r;
	if(l==r)
	{
		tree[cur].left=tree[cur].right=tree[cur].now=1;
		return ; 
	} 
	int m=(l+r)>>1;
	build(l,m,cur<<1);
	build(m+1,r,cur<<1|1);
	pushup(cur);
}
void update(int tar,int val,int cur)
{
	if(tree[cur].l==tree[cur].r)
	{
		a[tree[cur].l]=val;
		return ;
	}
	if(tar<=tree[cur<<1].r) update(tar,val,cur<<1);
	else update(tar,val,cur<<1|1);
	pushup(cur);
}
int query(int L,int R,int cur)
{
	if(L<=tree[cur].l&&tree[cur].r<=R) return tree[cur].now;
	if(R<=tree[cur<<1].r) return query(L,R,cur<<1);
	if(L>tree[cur<<1].r) return query(L,R,cur<<1|1);
	int res=max(query(L,R,cur<<1),query(L,R,cur<<1|1));
	int ll=min(tree[cur<<1].r-L+1,tree[cur<<1].right);
	int rr=min(R-tree[cur<<1].r,tree[cur<<1|1].left);
	if(a[tree[cur<<1].r]<a[tree[cur<<1].r+1]) res=max(res,ll+rr);
	return res;
}
int main()
{
	int t,n,m,x,y;
	char s[2];
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(int i=0;i<n;i++) scanf("%d",&a[i]);
		build(0,n-1,1);
		while(m--)
		{
			scanf("%s%d%d",s,&x,&y);
			if(s[0]=='U') update(x,y,1);
			else
			{
				int ans=query(x,y,1);
				printf("%d\n",ans);
			}
		}
	} 
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值