1. 程式人生 > >HDU3308 LCIS(線段樹區間合併)

HDU3308 LCIS(線段樹區間合併)

LCIS

傳送門1傳送門2 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<=105). The next line has n integers(0<=val<=105). The next m lines each has an operation: UAB(0<=A,n,0<=B=105) OR QAB(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

題意

找最長上升子串(區間).

分析

線段樹區間合併. 注意到在[l,r]中的LCIS,可能在左兒子,可能在右兒子,還可能跨越左右. 跨越左右的即為左兒子最長上升字尾+右兒子最長上升字首.故線段樹需維護三個量:最長上升前後綴與子串(區間). 對於每個節點,

Tree[p].lmx>=Tree[p<<1
].lmx, Tree[p].rmx>=Tree[p<<1|1].rmx, Tree[p].mx >=max(Tree[p<<1].mx,Tree[p<<1|1].mx

另外,若左兒子最右邊的數<右兒子左邊的數則左後綴與右字首之和為一個待選項.此時左後綴與右字首也有另外的待選項.

CODE

#include<iostream>
#include<cstdio>
#define FOR(i,a,b) for(int i=(a),i##_END_=(b);i<=i##_END_;i++)
#define Lson l,mid,p<<1
#define Rson mid+1,r,p<<1|1
#define N 100005

using namespace std;
void Rd(int &x) {
    char c;x=0;
    while((c=getchar())<48);
    do x=(x<<1)+(x<<3)+(c^48);
    while((c=getchar())>47);
}
int n,m;
int A[N];
struct SegT {int mx,lmx,rmx;} Tree[N<<2];

void Up(int l,int r,int p){
    int len=r-l+1,mid=(l+r)>>1;
    Tree[p].lmx=Tree[p<<1].lmx;
    Tree[p].rmx=Tree[p<<1|1].rmx;
    Tree[p].mx=max(Tree[p<<1].mx,Tree[p<<1|1].mx);
    if(A[mid]<A[mid+1]){
        if(Tree[p].rmx==(len>>1))Tree[p].rmx+=Tree[p<<1].rmx;
        if(Tree[p].lmx==len-(len>>1))Tree[p].lmx+=Tree[p<<1|1].lmx;
        Tree[p].mx=max(Tree[p].mx,Tree[p<<1].rmx+Tree[p<<1|1].lmx);
    }
}

int Query(int l,int r,int nl,int nr,int p) {
    if(l>=nl&&r<=nr)return Tree[p].mx;
    int Mx=1,mid=(l+r)>>1;
    if(nl<=mid) Mx=Query(l,mid,nl,nr,p<<1);
    if(nr>=mid+1) Mx=max(Mx,Query(mid+1,r,nl,nr,p<<1|1));
    if(A[mid]<A[mid+1])
        Mx=max(Mx,min(mid-nl+1,Tree[p<<1].rmx)+min(nr-mid,Tree[p<<1|1].lmx));
    return Mx;
}

void Build(int l,int r,int p){
    if(l==r){
        Tree[p].mx=Tree[p].lmx=Tree[p].rmx=1;
        return;
    }
    int mid=(l+r)>>1;
    Build(Lson),Build(Rson);
    Up(l,r,p); 
}

void Update(int l,int r,int x,int k,int p){
    if(l==r){
        A[l]=k;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)Update(l,mid,x,k,p<<1);
    else Update(mid+1,r,x,k,p<<1|1);
    Up(l,r,p);
}

int main() {
    int T,a,b;
    char chr[2];
    scanf("%d",&T);
    while(T--) {
        scanf("%d %d",&n,&m);
        FOR(i,1,n)Rd(A[i]);
        Build(1,n,1);
        while(m--) {
            scanf("%s",chr);
            Rd(a),Rd(b);
            if(chr[0]=='Q') printf("%d\n",Query(1,n,a+1,b+1,1));
            else Update(1,n,a+1,b,1);
        }
    }
    return 0;
}