LCIS

LCIS

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2658    Accepted Submission(s): 1152


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
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
 
 
/*思路:*/
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100000
typedef struct infor
{
	int l,r; //l是左孩子,r是右孩子
	int lnum,rnum; //lnum序列最左边的值,rnum序列最右边值
	int len,llen,rlen;	//llen从最左边开始的最长递增序列元素个数
						//rlen..最右边........................
						//最大递增序列值
}infor;
infor t[4*MAX] ;
int a[MAX + 1] ;
int max(int b, int c)
{
	return b>c?b:c ;
}
void up(int rt , int m ,  int lenl , int lenr )
{
	t[rt].len = max(t[rt*2].len ,t[rt*2 + 1].len); //中间的最长递增序列
	t[rt].llen = t[rt*2].llen ; //左边的递增序列
	t[rt].rlen = t[rt*2 + 1].rlen ;	//右边的递增序列
	if(t[rt*2].rnum < t[rt*2 + 1].lnum )//开始合并两个序列,如果第一个序列的最右边的元素小于第二个
										//序列的最左边的首元素
	{
		//分别更新中间,左边,右边的最长序列	
		t[rt].len = max(t[rt*2].rlen + t[rt*2 + 1 ].llen, t[rt].len );
		if(t[rt*2].llen >= lenl )
			t[rt].llen +=t[rt*2 + 1].llen ;
		if(t[rt*2 + 1].rlen >= lenr)
			t[rt].rlen +=t[rt*2].rlen ;	
	}
}

void create(int rt, int l , int r)
{
	t[rt].l = l ; 
	t[rt].r = r ;
	if(l == r)
	{
		t[rt].lnum = a[l] ;
		t[rt].rnum = a[l] ;
		t[rt].len = 1 ;
		t[rt].llen = 1 ;
		t[rt].rlen = 1 ;
		return ;
	}
	int mid = (l + r) / 2;
	create(rt*2 , l , mid );
	create(rt*2 + 1 , mid + 1 , r );
	t[rt].lnum = t[rt*2].lnum ;
	t[rt].rnum = t[rt*2 + 1].rnum ;
	up(rt , mid , mid - l + 1 , r - mid );

}

void update(int rt, int l, int r , int pos , int val)
{
	if(t[rt].l == t[rt].r)
	{
		t[rt].lnum = val;
		t[rt].rnum = val;
		return ;
	}
	int mid = (t[rt].l + t[rt].r ) / 2 ;
	if(pos > mid )
		update(rt*2 + 1 ,  mid + 1 , r , pos , val );
	else
		update(rt*2 , l , mid , pos , val );
	t[rt].lnum = t[rt*2].lnum ;
	t[rt].rnum = t[rt*2 + 1].rnum ;
	up( rt , mid , mid - l + 1 , r - mid );
}
int min(int b,int c)
{
	return b<c?b:c ;
}
int cal(int rt , int l , int r , int x , int y )
{
	if(x <= l && y >= r)
		return t[rt].len;
	
	int mid = (t[rt].l+t[rt].r)/2;
	if(x > mid )
		return cal(rt*2 + 1 , mid +1 , r , x , y);
	else if(y <= mid)
		return cal(rt*2 , l ,mid , x , y);
	int ret=max(cal(rt*2 , l , mid , x , y ),cal(rt*2 + 1 , mid + 1 , r , x , y ));
	if(t[rt*2].rnum<t[rt*2 + 1].lnum )
		/*下面那句的解释:min(y,mid+t[rt*2+1].llen)即取右边的最小值,同时因为是一个子区间,可能不会包含整个左递增区间
		类似于	左边序列:1,2,3,4,5 右边序列:6,7,3,2,1,如果如果只取到右边第一位,那么最小就是y,如果取到右边第五个,
		那么只能取到mid+t[tr*2+1].llen(因为要求递增),原理是这样*/
		return ret = max(ret , min(y,mid+t[rt*2+1].llen)-max(x,mid-t[rt*2].rlen+1)+1);
	//	return ret=max(ret , t[rt*2].rlen+t[rt*2+1].llen);
	return ret ;
}
int main()
{
	int Case;
	scanf("%d",&Case);
	while(Case --)
	{
		int n , m , i ;
		scanf("%d %d",&n,&m);
	
		for( i = 0 ; i < n ; i ++)
			scanf("%d",&a[i]);
		create(1,0,n-1);
		while(m--)
		{
			char ch[12];
			int x,y;
			scanf("%s %d %d",ch,&x,&y);
			if(ch[0]=='U')
				update(1,0,n-1,x,y);
			if(ch[0]=='Q')
				printf("%d\n",cal(1,0,n-1,x,y));
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值