LCIS HDU - 3308(线段树 单点更新+区间合并)

LCIS

题目链接:HDU - 3308

题意:标号1~n的数,两种操作:U  a   b:下标为a的数改为b;Q  a   b:查询区间[a, b]中的最长连续递增子序列;

思路:对于区间[l, r] ;lmax表示以l为起点的最长连续递增子序列,rmax表示以r为终点的最长连续递增子序列,Max表示区间[l, r]中的最长连续递增子序列;

对于两个相邻的区间,如果左区间的最后一个数小于右区间的第一个数,那么左右区间就可以合并左的rmax+右的lmax;

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct node{
	int l, r, len, lmax, rmax, Max; 
}tr[maxn<<2];
int a[maxn];
void pushup(int m){
	int mid=(tr[m].l+tr[m].r)>>1;
	int x=a[mid], y=a[mid+1];
	if(x<y){
		tr[m].lmax=tr[m<<1].lmax;
		if(tr[m<<1].lmax==tr[m<<1].len) tr[m].lmax+=tr[m<<1|1].lmax;
		tr[m].rmax=tr[m<<1|1].rmax;
		if(tr[m<<1|1].rmax==tr[m<<1|1].len) tr[m].rmax+=tr[m<<1].rmax;
		tr[m].Max=max(max(max(tr[m<<1].Max, tr[m<<1|1].Max), max(tr[m].lmax, tr[m].rmax)), tr[m<<1].rmax+tr[m<<1|1].lmax);
	}
	else{
		tr[m].lmax=tr[m<<1].lmax;
		tr[m].rmax=tr[m<<1|1].rmax;
		tr[m].Max=max(tr[m<<1].Max, tr[m<<1|1].Max);
	}
}
void build(int m, int l, int r){
	tr[m].l=l;
	tr[m].r=r;
	tr[m].len=r-l+1;
	if(l==r){
		tr[m].lmax=tr[m].rmax=tr[m].Max=1;
		return;
	}
	int mid=(l+r)>>1;
	build(m<<1, l, mid);
	build(m<<1|1, mid+1, r);
	pushup(m);
}
void updata(int m, int index, int val){
	if(tr[m].l==tr[m].r){
		a[index]=val;
		return;
	}
	int mid=(tr[m].l+tr[m].r)>>1;
	if(index<=mid) updata(m<<1, index, val);
	else updata(m<<1|1, index, val);
	pushup(m);
}
int query(int m, int l, int r){
	if(tr[m].l==l&&tr[m].r==r){
		return tr[m].Max;
	}
	int mid=(tr[m].l+tr[m].r)>>1;
	int temp;
	if(r<=mid) temp=query(m<<1, l, r);
	else if(l>mid) temp=query(m<<1|1, l, r);
	else{
		int x=a[mid], y=a[mid+1];
		if(x<y){
			node t;
			t.lmax=query(m<<1, l, mid);
			t.rmax=query(m<<1|1, mid+1, r);
			temp=max(max(t.lmax, t.rmax), min(mid-l+1, tr[m<<1].rmax)+min(r-mid, tr[m<<1|1].lmax));
		}
		else{
			temp=max(query(m<<1, l, mid), query(m<<1|1, mid+1, r));
		}
	}
	return temp;
}
void print(int m){
	if(tr[m].l==tr[m].r){
		printf("%d ", a[tr[m].l]);
		return;
	}
	print(m<<1);
	print(m<<1|1);
}
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		int n, m;
		scanf("%d%d", &n, &m);
		for(int i=1; i<=n; i++){
			scanf("%d", &a[i]);
		}
		build(1, 1, n);
		char op[5];
		int a, b;
		while(m--){
			scanf("%s%d%d", op, &a, &b);
			a++, b++;
			if(op[0]=='Q') printf("%d\n", query(1, a, b));
			else updata(1, a, --b);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值