HDU3308 LCIS【线段树 区间合并】

LCIS

http://acm.hdu.edu.cn/showproblem.php?pid=3308

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


 

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

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

Author

shǎ崽

 

Source

HDOJ Monthly Contest – 2010.02.06

 

题意

给出n个数,有两种操作一种为(U x y)将x点的值改为y,另一种为(Q x y)求区间[x,y]最长连续递增序列长度

题解

sum[i]表示i控制的区间中的最长严格递增子序列长度
lsum[i]表示以i为前缀的最长严格递增子序列长度
rsum[i]表示以i为后缀的最长严格递增子序列长度 

 

查找在[L,R]中以i为前缀或后缀的最大严格递增子序列是由如下语句实现

min(rsum[rt<<1],m-L+1)+min(lsum[rt<<1|1],R-m)

开始时自己写了函数查询,却发现过不了,也不知道查询函数错在哪。也就只能用上面的语句了。

//调用此函数的前提是l在区间[L,R]内 
//查询以l为起点向后,终点在[L,R]区间内的最长严格递增子序列的长度 
int lquery(int L,int R,int l,int r,int rt)
{
	if(l+lsum[rt]-1<=R) return lsum[rt];
	int m=(l+r)>>1;
	if(m>=R) return lquery(L,R,ls);
	int len=lsum[rt<<1];
	if(len=m-l+1&&a[m]<a[m+1]) len+=lquery(L,R,rs);
	return len;
}

//调用此函数的前提是r在区间[L,R]内 
//查询以r为起点向前,终点在[L,R]区间内的最长严格递增子序列的长度 
int rquery(int L,int R,int l,int r,int rt)
{
	if(r-rsum[rt]+1>=L) return rsum[rt];
	int m=(l+r)>>1;
	if(m<L) return rquery(L,R,rs);
	int len=rsum[rt<<1|1];
	if(len=r-m&&a[m]<a[m+1]) len+=lquery(L,R,ls);
	return len;
}

C++代码

#include<iostream>
#include<algorithm>

using namespace std;

#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1

const int N=100100;

//sum[i]表示i控制的区间中的最长严格递增子序列长度
//lsum[i]表示以i为前缀的最长严格递增子序列长度
//rsum[i]表示以i为后缀的最长严格递增子序列长度 
int sum[N<<2],lsum[N<<2],rsum[N<<2],a[N];

void pushup(int l,int r,int rt)
{
	int m=(l+r)>>1;
	
	sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
	if(a[m]<a[m+1]) sum[rt]=max(sum[rt],rsum[rt<<1]+lsum[rt<<1|1]);
	
	lsum[rt]=lsum[rt<<1];
	if(lsum[rt]==m-l+1&&a[m]<a[m+1]) lsum[rt]+=lsum[rt<<1|1];
	
	rsum[rt]=rsum[rt<<1|1];
	if(rsum[rt]==r-m&&a[m]<a[m+1]) rsum[rt]+=rsum[rt<<1];
}

void build(int l,int r,int rt)
{
	if(l==r)
	{
		sum[rt]=lsum[rt]=rsum[rt]=1;
		return;
	}
	int m=(l+r)>>1;
	build(ls);
	build(rs);
	pushup(l,r,rt);
}

void update(int L,int C,int l,int r,int rt)
{
	if(l==r)
	{
		a[l]=C;
		return;
	}
	int m=(l+r)>>1;
	if(L<=m)
	  update(L,C,ls);
	else
	  update(L,C,rs);
	pushup(l,r,rt);
}

int query(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R) return sum[rt];
	int m=(l+r)>>1;
	if(R<=m) return query(L,R,ls);
	if(L>m) return query(L,R,rs);
	int len=max(query(L,R,ls),query(L,R,rs));
	int tmp;
	if(a[m]<a[m+1]) len=max(len,min(rsum[rt<<1],m-L+1)+min(lsum[rt<<1|1],R-m));
	return len;
}

int main()
{
	int t,n,m,A,B;
	char q;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
		  scanf("%d",&a[i]);
		build(1,n,1);
		while(m--)
		{
			scanf(" %c%d%d",&q,&A,&B);
			if(q=='U')
			  update(A+1,B,1,n,1);
			else 
			  printf("%d\n",query(A+1,B+1,1,n,1));
		}
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值