hdu3308(线段树,区间合并)

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

LCIS

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


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
 


题意:求区间内最大连续递增子序列。

先自己做了遍,但是一直WA,找不到错哪了。然后找了大牛的代码看了下,好高端,自己写了下。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define M 100050
#define LL L,m,c<<1
#define RR m+1,R,c<<1|1
#define max(a,b) a>b?a:b
struct node{
	int lm,rm,sm;
};
int lm[M*5],rm[M*5],sm[M*5],da[M];
void push(int L,int R,int c)
{
	int m=(L+R)>>1;
	lm[c]=lm[c<<1];rm[c]=rm[c<<1|1];
	sm[c]=max(sm[c<<1],sm[c<<1|1]);
	if(da[m]<da[m+1])
	{
		if(lm[c<<1]==m-L+1) lm[c]+=lm[c<<1|1];
		if(rm[c<<1|1]==R-m) rm[c]+=rm[c<<1];
		sm[c]=max(sm[c],rm[c<<1]+lm[c<<1|1]);
	}
}
void ori_tree(int L,int R,int c)
{
	int m=(L+R)>>1;
	if(L==R)
	{
		scanf("%d",&da[L]);
		lm[c]=rm[c]=sm[c]=1;
		//printf("%d %d %d %d %d\n",L,R,lm[c],rm[c],sm[c]);
	}
	else
	{
		ori_tree(LL);
		ori_tree(RR);
		push(L,R,c);
		//printf("%d %d %d %d %d\n",L,R,lm[c],rm[c],sm[c]);
	}
}
void updata(int i,int num,int L,int R,int c)
{
	if(L==R)
		da[L]=num;
	else
	{
		int m=(L+R)>>1;
		if(i<=m) updata(i,num,LL);
		else updata(i,num,RR);
		push(L,R,c);
	}
}
node sum(int l,int r,int L,int R,int c)
{
	node lv,rv,sv;
	if(L==l&&R==r)
	{
		sv.lm=lm[c];
		sv.rm=rm[c];
		sv.sm=sm[c];
		return sv;
	}
	else
	{
		int m=(L+R)>>1;
		if(r<=m) return sum(l,r,LL);
		else if(l>m) return sum(l,r,RR);
		else
		{
			lv=sum(l,m,LL);
			rv=sum(m+1,r,RR);
			sv.lm=lv.lm;sv.rm=rv.rm;
			sv.sm=max(lv.sm,rv.sm);
			if(da[m]<da[m+1])
			{
				if(lv.lm==m-L+1) sv.lm+=rv.lm;
				if(rv.rm==R-m) sv.rm+=lv.rm;
				sv.sm=max(sv.sm,lv.rm+rv.lm);
			}
			return sv;
		}
	}
}

int main()
{
	int t,m,n,l,r;
	char str[20];
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&m,&n);
		ori_tree(1,m,1);
		while(n--)
		{
			scanf("%s%d%d",str,&l,&r);
			if(str[0]=='Q')
				printf("%d\n",sum(l+1,r+1,1,m,1).sm);
			else updata(l+1,r,1,m,1);
		}
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值