HDU 3308【线段树--c++版区间合并,dp】

 

LCIS

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


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
 

Author
shǎ崽
 

Source
 

Recommend
wxl
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
//题目:LCIS hdu 3308


 //求任意长度的最长连续子序列,且随时会改变序列里面的值




#include <stdio.h>
#include <memory.h>
#include <iostream>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define Maxn 100100
using namespace std;


int node[Maxn];
struct point {
    int Msum;//范围内的最大的长度
    int lsum, rsum;//从最左端起最长的长度,从最右端起最长的长度
    int lnum, rnum;//最左端的数字,最右端的数字
    bool mark;//是否这一整段范围内的数都满足,即从左起的最大长度是整段的长度
    void init() {
        Msum = lsum = rsum = mark = 1;
    }
    void PushUp(point, point);
}pot[4 * Maxn];


inline int Max(int a, int b) {
    if(a > b) return a;
    return b;
}


void scan_d(int &a) {
    char in;
    in = getchar();
    while( in != '-' && (in > '9' || in < '0')) {
        in = getchar();
    }
    int mark = 0;
    if (in =='-') {
        mark = 1;
        a = 0;
    } else  a = in - '0';
    while (in = getchar(), in >= '0' && in <= '9') {
        a = a * 10 + in - '0';
    }
    if (mark) a = -a;
}


void point::PushUp(point ls, point rs) {//合并ls,rs两个区间
    lsum = ls.lsum;
    rsum = rs.rsum;
    lnum = ls.lnum;
    rnum = rs.rnum;
    Msum = Max(ls.Msum, rs.Msum);
    if (ls.rnum < rs.lnum) {
        if(ls.mark&&rs.mark) {//如果左右的区间都是全的那么父亲区间也要取全
            Msum = lsum = rsum = lsum + rsum;
            mark = 1;
            return ;
        }
        mark = 0;//注意
        if (ls.mark) lsum += rs.lsum;
        else if (rs.mark)  rsum += ls.rsum;
        Msum = Max(Msum, rs.lsum + ls.rsum);
    }
    mark = 0;//注意
}


void Build(int l, int r, int rt) {
    if (l == r) {
        pot[rt].init();
        pot[rt].lnum = pot[rt].rnum = node[l];//注意是node[l]
        return ;
    }
    int m = (r + l) >> 1;
    Build(lson);
    Build(rson);
    pot[rt].PushUp(pot[rt<<1], pot[rt<<1|1]);
}


void UpDate(int a, int b, int l, int r, int rt) {
    if (l == r) {
        pot[rt].lnum = pot[rt].rnum = b;
        return ;
    }
    int m = (r + l) >> 1;
    if (a <= m) UpDate(a, b, lson);
    else UpDate(a, b, rson);
    pot[rt].PushUp(pot[rt<<1], pot[rt<<1|1]);
}


point query(int L, int R, int l, int r, int rt) {
    point ret;
    if (L > r || R < l) {
        ret.Msum = -1;
        return ret;
    }
    if (L <= l && R >= r) {
        return pot[rt];
    }
    int m = (r + l) >> 1;
    point a = query(L, R, lson);//与c不一样的地方
    point b = query(L, R, rson);
    if (a.Msum == -1)  return b;
    if (b.Msum == -1)  return a;
    ret.PushUp(a, b);
    return ret;
}




int main()
{
    int casenumber, n, m, a, b;
    scan_d(casenumber);
    while (casenumber--) {
        scan_d(n);
        scan_d(m);
        for (int i = 1; i <= n; i++) scan_d(node[i]);
        Build(1, n, 1);
        char str;
        for (int i = 0; i < m; i ++) {
            str = getchar();
            scan_d(a);
            scan_d(b);
            if (str == 'U') {
                UpDate(a + 1, b, 1, n, 1);//注意题目的范围是从0-n-1
            }
            else {
                point h = query(a + 1, b + 1, 1, n, 1);
                printf("%d\n", h.Msum);
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值