HDU3308

题目链接:https://vjudge.net/problem/HDU-3308

解题思路:以len[ ]保存区间内的最长单调递增区间长度,以llen[ ]保存区间内从第一个元素开始的最长单调递增区间长度,以rlen[ ]保存区间内以最后一个元素为结尾的最长单调递增区间长度。【 b( ̄▽ ̄)d 好拗口啊~】

        重点主要是在pushup()的区间合并操作和query( )的查询操作,都是在下精心策划出来的,希望看官能稍加体味,不吝赐教。

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=1e5+6;
int llen[maxn<<2],rlen[maxn<<2],len[maxn<<2],tree[maxn];
void pushup(int l,int r,int rt){
    int m=(l+r)>>1;
    llen[rt]=llen[rt<<1];   rlen[rt]=rlen[rt<<1|1];
    if(tree[m+1]>tree[m]){
        if(llen[rt<<1]==m-l+1)   llen[rt]+=llen[rt<<1|1];
        if(rlen[rt<<1|1]==r-m)   rlen[rt]+=rlen[rt<<1];
        len[rt]=max(max(len[rt<<1],len[rt<<1|1]),rlen[rt<<1]+llen[rt<<1|1]);
    }
    else
        len[rt]=max(len[rt<<1],len[rt<<1|1]);
}
void build(int l,int r,int rt){
    if(l==r){
        scanf("%d",&tree[l]);
        len[rt]=llen[rt]=rlen[rt]=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(l,r,rt);
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R)
        return len[rt];
    int m=(l+r)>>1;
    if(L<=m&&m<R){
        int l1=query(L,R,lson),l2=query(L,R,rson);
        if(tree[m]<tree[m+1]){
            int le=max(L,m-rlen[rt<<1]+1),ri=min(R,m+llen[rt<<1|1]);
            return max(max(l1,l2),ri-le+1);
        }
        return max(l1,l2);
    }
    else if(R<=m)
        return query(L,R,lson);
    else
        return query(L,R,rson);
}
void update(int d,int c,int l,int r,int rt){
    if(d==l && d==r){
        tree[d]=c;
        return;
    }
    int m=(l+r)>>1;
    if(m>=d)
        update(d,c,lson);
    else
        update(d,c,rson);
    pushup(l,r,rt);
}
int main(){
    int T;
    scanf("%d\n",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        build(0,n-1,1);

        while(m--){
            char c[3];
            int a,b;
            scanf("%s %d %d",c,&a,&b);
            if(c[0]==‘Q‘)
                printf("%d\n",query(a,b,0,n-1,1));
            else
                update(a,b,0,n-1,1);
        }
    }
    return 0;
}
时间: 2024-12-29 01:30:46

HDU3308的相关文章

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

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

HDU3308 LCIS

Time Limit: 2000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u 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 increas

HDU3308(LCIS) 线段树好题

题目链接:传送门 题目大意:给你n个数,m个操作.操作有两种:1.U x y 将数组第x位变为y   2. Q x y 问数组第x位到第y位连续最长子序列的长度.对于每次询问,输出一个答案 题目思路:线段树单点修改区间合并 这道题题目好在对pushup的理解,我们在向上更新的时候有注意情况的区分 1.如果左区间的最右边的值小于右区间最左边的值,则有一个待定答案是左儿子的右区间+右儿子的左区间 2.如果不符合第一个条件,则有一个待定答案是左区间最大值和右区间最大值中较大的那一个. 有一点要特别注意

【解题报告】hdu3308 LCIS

http://acm.hdu.edu.cn/showproblem.php?pid=3308 大意:输入n个数,m个操作.操作有两种:1.U x y 将数组第x位变为y   2. Q x y 问数组第x位到第y位连续最长子序列的长度. 题目主要考察的就是对pushup逆向更新的运用,就是更改树底(1号操作),从树底下往上更新... 至于最长子序列,长度为1的区间最长子序列当然就是自己,对于两个区间的最长子序列合并,无非就是两种情况,一种就是两个区间的最长子序列接上了,第二种就是没接上,取两个最长

[hdu3308]线段树

题意:单点更新,区间LCIS(最长连续递增序列)查询.具备区间合并维护的性质,不用线段树用什么~ 1 #pragma comment(linker, "/STACK:10240000,10240000") 2 3 #include <iostream> 4 #include <cstdio> 5 #include <algorithm> 6 #include <cstdlib> 7 #include <cstring> 8 #

HDU3308 线段树区间合并

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 ,简单的线段树区间合并. 线段树的区间合并:一般是要求求最长连续区间,在PushUp()函数中实现区间合并操作. 解法: 由于对于一个区间的最长序列来说,最优解要么完全在左半序列,要么完全在右半序列,要么跨越中间点.所以可以构造线段树,维护结点区间的三个元素:最长上升前缀len[].l,最长上升后缀len[].r,最长上升序列len[].m.所以对于一个区间来说,有这样两种情况: 1. 左儿子

hdu3308 线段树 求最大连续递增序列

对每个节点   left表示该节点前缀最大连续上升 right为后缀最大连续上升 all为整个区间最大连续上升 pre为区间左边值   after为右边值 其他和别的线段树都差不多       关键是看如何合并 #include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define LL(x) (x<<1) #define RR(x) ((x<<1)

hdu3308 线段树(区间合并)

给n个数字 U表示第A个数改为B.A是从0开始. Q输出最大的递增序列个数. 考虑左边,右边,和中间. #include<stdio.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 100010 int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2]; int num[maxn]; int max(int x,int

hdu3308—LCIS

题目链接 http://hdu.hustoj.com/showproblem.php?pid=3308 问题描述 给出n个整数,有两种操作 1)U A B:用B取代第A个数(下标从0开始) 2)Q A B:输出在[A,B]中最长连续递增子序列的长度分析 给出一个序列,两种操作,分别是单点更新值和查询区间的最长连续递增子序列长 度,典型的线段树问题 首先考虑线段树的节点需要记录哪些值: 1)包含左端点的最长连续递增子序列长度,记作pre[] 2)包含右端点的最长连续递增子序列长度,记作suf[]