hdu3308 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<=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

这题属于线段树区间合并,题意是求一个区间内的最长连续递增子序列。首先用线段树维护7个节点,l,r,llen,rlen,tlen,lnum,rnum;(llen,rlen表示这段区间从最左(右)向右(左)可以持续的最大递增子序列长度。tlen表示这条线段的最大递增子序列长度,lnum,rnum表示这段线段最左边和左右边的值)。我在一开始建树的时候就把7个初始化好了,这样下面就比较方便。

这里的难点是查询,当查询区间全落在左子树或者右子树的时候比较简单,直接算子树的最大长度,但落在中间的时候要考虑合并的值,这里合并时注意不能直接用b[i*2].rlen+b[i*2+1].llen,因为查询的区间(l,r)可能大于b[2*i+1].l+b[2*i+1].llen-1或者小于b[2*i].r-b[2*i].rlen+1,这样就要分类讨论。这里卡了很长时间= =。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
int a[100005],num;
char s[10];
struct node{
	int l,r,llen,rlen,tlen,lnum,rnum;
}b[8*100005];
int max(int a,int b){
	return a>b?a:b;
}

void build(int l,int r,int i)
{
	int mid;
	b[i].l=l;b[i].r=r;
	if(l==r){
		b[i].lnum=b[i].rnum=a[l];
		b[i].rlen=b[i].llen=b[i].tlen=1;
		return;
	}
	mid=(l+r)/2;
	build(l,mid,i*2);
	build(mid+1,r,i*2+1);
	b[i].lnum=b[i*2].lnum;
	b[i].rnum=b[i*2+1].rnum;
	b[i].tlen=max(b[i*2].tlen,b[i*2+1].tlen);
	if(b[i*2].rnum<b[i*2+1].lnum){
		b[i].tlen=max(b[i].tlen,b[i*2].rlen+b[i*2+1].llen);
	}
	b[i].llen=b[i*2].llen;
	if(b[i*2].rnum<b[i*2+1].lnum && b[i*2].llen==(b[i*2].r-b[i*2].l+1)){
		b[i].llen+=b[i*2+1].llen;
	}
	b[i].rlen=b[i*2+1].rlen;
	if(b[i*2].rnum<b[i*2+1].lnum && b[i*2+1].rlen==(b[i*2+1].r-b[i*2+1].l+1)){
		b[i].rlen+=b[i*2].rlen;
	}
}

void update(int index,int num,int i)
{
	int mid;
	if(b[i].l==b[i].r){
		b[i].rnum=b[i].lnum=num;return;
	}
	if(b[i*2].r-b[i*2].l+1>=index)update(index,num,i*2);
	else update(index-(b[i*2].r-b[i*2].l+1),num,i*2+1);
	b[i].lnum=b[i*2].lnum;
	b[i].rnum=b[i*2+1].rnum;
	b[i].tlen=max(b[i*2].tlen,b[i*2+1].tlen);
	if(b[i*2].rnum<b[i*2+1].lnum){
		b[i].tlen=max(b[i].tlen,b[i*2].rlen+b[i*2+1].llen);
	}
	b[i].llen=b[i*2].llen;
	if(b[i*2].rnum<b[i*2+1].lnum && b[i*2].llen==(b[i*2].r-b[i*2].l+1)){
		b[i].llen+=b[i*2+1].llen;
	}
	b[i].rlen=b[i*2+1].rlen;
	if(b[i*2].rnum<b[i*2+1].lnum && b[i*2+1].rlen==(b[i*2+1].r-b[i*2+1].l+1)){
		b[i].rlen+=b[i*2].rlen;
	}
}

void question(int l,int r,int i)
{
	int mid,r1,l1;
	if(b[i].l==l && b[i].r==r){
		num=max(num,b[i].tlen);return;
	}
	mid=(b[i].l+b[i].r)/2;
	if(r<=mid)question(l,r,i*2);
	else if(l>mid)question(l,r,i*2+1);
	else if(l<=mid && r>mid){
		if(b[i*2].rnum<b[i*2+1].lnum){
			if(b[2*i+1].l+b[2*i+1].llen-1>=r)r1=r;
			else r1=b[2*i+1].l+b[2*i+1].llen-1;
			if(b[2*i].r-b[2*i].rlen+1<=l)l1=l;
			else l1=b[2*i].r-b[2*i].rlen+1;
			num=max(num,r1-l1+1);
		}
		question(l,mid,i*2);
		question(mid+1,r,i*2+1);
	}
}

int main()
{
	int n,m,i,j,T,c,d;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		build(1,n,1);
		for(i=1;i<=m;i++){
			scanf("%s",s);
			if(s[0]=='Q'){
				scanf("%d%d",&c,&d);
				num=0;
				question(c+1,d+1,1);
				printf("%d\n",num);
			}
			else if(s[0]=='U'){
				scanf("%d%d",&c,&d);
				update(c+1,d,1);
			}
		}
	}
	return 0;
}


你可能感兴趣的:(线段树)