线段树区间合并+最长连续递增子序列——HDU 3308

对应HDU题目:点击打开链接

LCIS
Time Limit: 2000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u

Submit Status

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
 

Source


题意:给出n个数,m个询问,每个询问包含 (c,a,b) ,c=U时,把下标为a的值改为b,c=Q时,求[a,b]之间的最长连续递增子序列,并输出

思路:线段树区间合并;

对于一段区间[l,r],mid为中间值,要求[a,b]之间(其中a,b在[l,r]内)的lcis,则最长连续递增子序列要么在mid左边,要么在mid右边,要么是mid左右两边都有。所以线段树区间维护的就是3个数组,一个是该区间的lcis,用lcis[rt]表示,一个是从区间左边界数起连续递增序列的个数llcis[rt],一个是从区间右边界数起连续递减序列的个数rlcis[rt]。

试了下两种╮(╯_╰)╭

       [0,9]                      和                  [0,9]

[0,4]      [4,9]                                [0,4]    [5,9]


#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#define ms(x,y) memset(x,y,sizeof(x))
#define eps 1e-6
const int MAXN=400000+10;
const int INF=1<<30;
using namespace std;
int value[MAXN/4];
int lcis[MAXN];
int llcis[MAXN];
int rlcis[MAXN];

void up(int rt, int mid, int len)
{
	llcis[rt] = llcis[rt<<1];
	rlcis[rt] = rlcis[rt<<1|1];
	lcis[rt] = max(lcis[rt<<1], lcis[rt<<1|1]);
	if( value[mid+1] > value[mid] ){
		if(llcis[rt] == len-(len>>1)) llcis[rt] += llcis[rt<<1|1];
		if(rlcis[rt] == (len>>1)) rlcis[rt] += rlcis[rt<<1];
		lcis[rt] = max(rlcis[rt<<1] + llcis[rt<<1|1], lcis[rt]);
	}
}

void update_change(int rt, int left, int right, int pos)
{
	if(left == right) return;
	if(right - left == 1){
		if(value[left] < value[right]){
			lcis[rt] = 2;
			llcis[rt] = 2;
			rlcis[rt] = 2;
		}
		else{
			lcis[rt] = 1;
			llcis[rt] = 1;
			rlcis[rt] = 1;
		}
		return;
	}
	int mid=(left+right)>>1;
	if(mid >= pos) update_change(rt<<1, left, mid, pos);
	else update_change(rt<<1|1, mid+1, right, pos);
	up(rt, mid, right-left+1);
}


int query(int rt, int left, int right, int l, int r)
{
	if(l == left && right == r)	return lcis[rt];
	int mid=(left + right)>>1;
	if(mid >= r) return query(rt<<1, left, mid, l, r);
	else if(mid < l) return query(rt<<1|1, mid+1, right, l, r);
	else{
		int len1=query(rt<<1, left, mid, l, mid);
		int len2=query(rt<<1|1, mid+1, right, mid+1, r);
		int len3=0;
		if(value[mid+1] > value[mid]) len3=min(rlcis[rt<<1], mid-l+1) + min(llcis[rt<<1|1], r-mid);
		return max(len1, max(len2,len3));
	}
}

void Initialize()
{
	for(int i=0; i<MAXN; i++){
		lcis[i]=1;
		llcis[i]=1;
		rlcis[i]=1;
	}
}

int main()
{
	//freopen("in.txt","r",stdin);
	int T;
	scanf("%d", &T);
	while(T--)
	{
		Initialize();
		char op;
		int n,m;
		int a,b;
		scanf("%d%d", &n,&m);
		for(int i=0; i<n; i++){
			scanf("%d", &value[i]);
			update_change(1,0,n-1,i);
		}
		while(m--)
		{
			scanf(" %c%d%d", &op,&a,&b);
			if(op == 'U'){
				value[a]=b;
				update_change(1,0,n-1,a);
			}
			else{
				if(b - a == 1 || b - a == 0){//求相邻的两个数或求一个数
					if(value[a] >= value[b]) printf("1\n");
					else printf("2\n");
				}
				else printf("%d\n", query(1,0,n-1,a,b));//求三个数以上
			}
		}
	}
	return 0;
}




#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#define ms(x,y) memset(x,y,sizeof(x))
#define eps 1e-6
const int MAXN=400000+10;
const int INF=1<<30;
using namespace std;
int value[MAXN];
int lcis[MAXN];
int llcis[MAXN];
int rlcis[MAXN];

void up(int rt, int len)
{
	int llen,rlen;
	llen=rlen=(len>>1) + 1;
	if((len&1) == 0) llen--;
	llcis[rt] = llcis[rt<<1];
	rlcis[rt] = rlcis[rt<<1|1];
	if(llcis[rt] == llen) llcis[rt] += llcis[rt<<1|1] - 1;
	if(rlcis[rt] == rlen) rlcis[rt] += rlcis[rt<<1] - 1;
	lcis[rt] = max(rlcis[rt<<1] + llcis[rt<<1|1] - 1, max(lcis[rt<<1], lcis[rt<<1|1]));
}

void update_change(int rt, int left, int right, int pos)
{
	if(right - left ==1){
		int lval=value[left];
		int rval=value[right];
		if(lval < rval){
			lcis[rt] = 2;
			llcis[rt] = 2;
			rlcis[rt] = 2;
		}
		else{
			lcis[rt] = 1;
			llcis[rt] = 1;
			rlcis[rt] = 1;
		}
		return;
	}
	int mid=(left+right)>>1;
	if(mid > pos) update_change(rt<<1, left, mid, pos);
	else if(mid < pos) update_change(rt<<1|1, mid, right, pos);
	else{
		update_change(rt<<1, left, mid, pos);
		update_change(rt<<1|1, mid, right, pos);
	}
	up(rt, right-left+1);
}


int query(int rt, int left, int right, int l, int r)
{
	if(l == left && right == r)	return lcis[rt];
	int mid=(left + right)>>1;
	if(mid >= r) return query(rt<<1, left, mid, l, r);
	else if(mid <= l) return query(rt<<1|1, mid, right, l, r);
	else{
		int len1=query(rt<<1, left, mid, l, mid);
		int len2=query(rt<<1|1, mid, right, mid, r);
		int len3=min(rlcis[rt<<1], mid-l+1) + min(llcis[rt<<1|1], r-mid+1) - 1;
		return max(len1, max(len2,len3));
	}
}

void Initialize()
{
	for(int i=0; i<MAXN; i++){
		lcis[i]=1;
		llcis[i]=1;
		rlcis[i]=1;
		value[i]=0;
	}
}

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("c:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
	int T;
	scanf("%d", &T);
	while(T--)
	{
		Initialize();
		char op;
		int n,m;
		int a,b;
		scanf("%d%d", &n,&m);
		for(int i=0; i<n; i++){
			scanf("%d", &value[i]);
			update_change(1,0,n-1,i);
		}
#if 0
		for(int j=1; j<=31; j++){
			cout<<j<<": "<<lcis[j]<<endl;
			cout<<"   "<<llcis[j]<<endl;
			cout<<"   "<<rlcis[j]<<endl;
		}
		cout<<endl;
#endif
		while(m--)
		{
			scanf(" %c%d%d", &op,&a,&b);
			//cin>>op>>a>>b;
			if(op == 'U'){
				value[a]=b;
				update_change(1,0,n-1,a);
			}
			else{
				if(b - a == 1 || b - a == 0){
					if(value[a] >= value[b]) printf("1\n");
					else printf("2\n");
				}
				else printf("%d\n", query(1,0,n-1,a,b));
			}
		}
	}
	return 0;
}






你可能感兴趣的:(线段树区间合并+最长连续递增子序列——HDU 3308)