HDU 3308 LCIS(线段树+区间合并+最长递增连续子串)

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.


#include<cstdio>  
#include<algorithm>  
#include<cstring>  
#include<cmath>  
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MAXN = 100100;
int val[MAXN];
int lsum[MAXN << 2], rsum[MAXN << 2], msum[MAXN << 2];

void PushUp(int l, int r,int rt)
{

	int m = (l + r)>>1;

	msum[rt] = max(msum[rt<<1], msum[rt<<1|1]); //更新msum 
	if (val[m] < val[m + 1]) msum[rt] = max(msum[rt], rsum[rt<<1] + lsum[rt<<1|1]);//满足条件左右子树可以合并

	lsum[rt] = lsum[rt<<1]; //更新lsum
	if (lsum[rt] == m - l + 1 && val[m] < val[m + 1]) lsum[rt] += lsum[rt<<1|1];//左子树是满的,满足条件左右子树可以合并

	rsum[rt] = rsum[rt<<1|1]; //更新rsum  
	if (rsum[rt] == r - m && val[m] < val[m + 1]) rsum[rt] += rsum[rt<<1];//右子树是满的,满足条件左右子树可以合并
}

//建立线段树且更新所有节点
void build( int l, int r,int rt)
{
	if (l == r)
	{
		msum[rt] = rsum[rt] = lsum[rt] = 1;
		return;
	}
	int m = (r + l) >> 1;
	build(lson);
	build(rson);
	PushUp(l, r,rt);
}

//将q号元素的值置换为v  
void update(int q, int v, int l, int r,int rt)
{
	if (l == r)
	{
		val[l] = v;
		msum[rt] = rsum[rt] = lsum[rt] = 1;
		return;
	}
	int m = (r + l)>>1;
	if (q <= m) update(q, v, lson);
	else update(q, v, rson);
	PushUp(l, r,rt);
}

int query(int L, int R, int l, int r, int rt)
{
	//在区间里
	if (L <= l && r <= R)
	{
		return msum[rt];
	}

	int m = (l + r) >> 1;
	if (R <= m) return query(L, R, lson);//在左子树
	else if (m<L) return query(L, R, rson);//在右子树
	//在左的右子树和右的左子树
	int res = max(query(L, R, lson), query(L, R, rson));
	int lsumx = min(R - m, lsum[rt<<1|1]);//[m+1,R]与[m+1,r]相交部分
	int rsumx = min(m - L + 1, rsum[rt<<1]);//[L,m]与[l,m]相交部分
	if (val[m]<val[m + 1]) res = max(res, lsumx + rsumx);
	return res;
}
int main()
{
	int T, n, m;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &n, &m);
		for (int i = 0; i < n; i++)
			scanf("%d", &val[i]);
		build(0,n-1,1);
		while (m--)
		{
			char str[10];
			int x, y;
			scanf("%s%d%d", str, &x, &y);
			if (str[0] == 'U')
				update(x, y, 0, n - 1, 1);
			else if (str[0] == 'Q')
				printf("%d\n", query(x, y, 0, n - 1, 1));
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值