LCIS HDU - 3308(线段树区间合并)

LCIS

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


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

题意:n个数从0到n-1,两种操作,第一种操作是U,A,B,把B位置的值用A来代替,第二种操作是查询区间【A,B】的最长连续严格上升序列。

思路:线段树区间合并题,维护3个变量,单点更新不需要pushdown,区间查询,查询和pushup的时候需要区间合并。

#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAXN = 100005;
struct NODE{
	int l,r;
	int ls,rs,maxs;
	//ls为从区间左边界开始的最长连续上升序列
	//rs为从区间右边界开始的最长连续上升序列
	//maxs为该区间的最长连续上升序列
}segTree[MAXN << 2];
int a[MAXN];

void pushup(int num)
{

    segTree[num].ls = segTree[num << 1].ls;//父节点的ls与左儿子的ls相同
    segTree[num].rs = segTree[num << 1 | 1].rs;//父节点的rs与右儿子的rs相同
    //不考虑左区间与右区间最长连续上升序列可以合并的话,父节点的maxs
    //为左右儿子大的那个maxs
    segTree[num].maxs = max(segTree[num << 1].maxs,segTree[num << 1 | 1].maxs);
    int mid = (segTree[num].l + segTree[num].r) >> 1;

    //如果左区间与右区间最长连续上升序列可以合并的话
    if(a[mid] < a[mid + 1]){
        //如果可以合并,还需更新左边区间的ls和右边区间的rs
        if(segTree[num << 1].ls == segTree[num << 1].r - segTree[num << 1].l + 1){
            segTree[num].ls += segTree[num << 1 | 1].ls;
        }
        if(segTree[num << 1 | 1].rs == segTree[num << 1 | 1].r - segTree[num << 1 | 1].l + 1){
            segTree[num].rs += segTree[num << 1].rs;
        }
        //更新maxs,左区间的rs+右区间的ls
        segTree[num].maxs = max(segTree[num].maxs,segTree[num << 1].rs + segTree[num << 1 | 1].ls);
    }
}

void build(int num,int l,int r)
{
	segTree[num].l = l;
	segTree[num].r = r;
	if(l == r){
        segTree[num].ls = segTree[num].rs = segTree[num].maxs = 1;
        return;
	}
	int mid = (l + r) >> 1;
	build(num << 1,l,mid);
	build(num << 1 | 1,mid + 1,r);
	pushup(num);
}
//单点更新,不需要pushdown
void update(int num,int pos)
{
	if(segTree[num].l == segTree[num].r)
		return;
	int mid = (segTree[num].l + segTree[num].r) >> 1;
	if(pos <= mid) update(num << 1,pos);
	else update(num << 1 | 1,pos);
	pushup(num);
}
//区间查询
int query(int num,int l,int r)
{
    if(segTree[num].l == l && segTree[num].r == r)
	  return segTree[num].maxs;
	int mid = (segTree[num].l + segTree[num].r) >> 1;
	int ans = 0;
	if(r <= mid){
        ans = max(ans,query(num << 1,l,r));
	}
	else if(l > mid){
        ans = max(ans,query(num << 1 | 1,l,r));
	}
	else{
        ans = max(ans,query(num << 1,l,mid));
        ans = max(ans,query(num << 1 | 1,mid + 1,r));
        //可以合并,注意要小于区间长度
        if(a[mid] < a[mid + 1]){
            ans = max(ans,min(mid - l + 1,segTree[num << 1].rs) + min(r - mid,segTree[num << 1 | 1].ls));
        }
	}
	return ans;
}
int main(void)
{
	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);
        while(m--){
            int l,r;
            char op[3];
            int pos,v;
            scanf("%s",op);
            if(op[0] == 'Q'){
               scanf("%d%d",&l,&r);
               l++,r++;
               printf("%d\n",query(1,l,r));
            }
            else{
               scanf("%d%d",&pos,&v);
               a[++pos] = v;
               update(1,pos);
            }
        }

	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/GYH0730/article/details/80368597