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 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

HDOJ Monthly Contest – 2010.02.06

线段树维护每个区间的三个值:从左开始数的最长单调上升序列,本区间内最长答案,以最右为结尾的最长单调上升序列。

每次合并的时候,如果左子树的右端点的值小于右子树的左端点的值,那么两段序列可以接起来……

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define ls l,mid,rt<<1
 7 #define rs mid+1,r,rt<<1|1
 8 using namespace std;
 9 const int mxn=100010;
10 int n,m;
11 int d[mxn];
12 struct node{
13     int cnt;int lans,rans;
14 }t[mxn<<2];
15 void update(int p,int l,int r,int rt){
16     if(l==r)return;
17     int mid=(l+r)>>1;
18     if(p<=mid)update(p,ls);
19     else update(p,rs);
20     t[rt].cnt=max(t[rt<<1].cnt,t[rt<<1|1].cnt);
21     t[rt].lans=t[rt<<1].lans;t[rt].rans=t[rt<<1|1].rans;
22     if(d[mid]<d[mid+1]){
23         t[rt].cnt=max(t[rt].cnt,t[rt<<1].rans+t[rt<<1|1].lans);
24         if(t[rt<<1].lans==mid-l+1)
25             t[rt].lans=t[rt<<1].lans+t[rt<<1|1].lans;
26         if(t[rt<<1|1].rans==r-mid)
27             t[rt].rans=t[rt<<1|1].rans+t[rt<<1].rans;
28     }
29     return;
30 }
31 void Build(int l,int r,int rt){
32     if(l==r){
33         t[rt].cnt=t[rt].lans=t[rt].rans=1;
34         return;
35     }
36     int mid=(l+r)>>1;
37     Build(ls);
38     Build(rs);
39     t[rt].cnt=max(t[rt<<1].cnt,t[rt<<1|1].cnt);
40     t[rt].lans=t[rt<<1].lans;
41     t[rt].rans=t[rt<<1|1].rans;
42     if(d[mid]<d[mid+1]){
43         t[rt].cnt=max(t[rt].cnt,t[rt<<1].rans+t[rt<<1|1].lans);
44         if(t[rt<<1].lans==mid-l+1)
45             t[rt].lans=t[rt<<1].lans+t[rt<<1|1].lans;
46         if(t[rt<<1|1].rans==r-mid)
47             t[rt].rans=t[rt<<1|1].rans+t[rt<<1].rans;
48     }
49     return;
50 }
51 int query(int L,int R,int l,int r,int rt){
52     if(L<=l && r<=R) return t[rt].cnt;
53     int mid=(l+r)>>1;
54     if(R<=mid)return query(L,R,ls);
55     if(mid<L)return query(L,R,rs);
56     else{
57         int res=max(query(L,R,ls),query(L,R,rs));
58         if(d[mid]<d[mid+1]){//如果结点所存答案长于区间长度,实际答案等于区间长度,用min维护
59             res=max(res,(min(t[rt<<1].rans,mid-L+1)+min(t[rt<<1|1].lans,R-mid)));
60         }
61         return res;
62     }
63 }
64 int main(){
65     int T;
66     scanf("%d",&T);
67     while(T--){
68         memset(t,0,sizeof 0);
69         int i,j;
70         scanf("%d%d",&n,&m);
71         for(i=1;i<=n;i++)scanf("%d",&d[i]);
72         Build(1,n,1);
73         char op[2];int a,b;
74         for(i=1;i<=m;i++){
75             scanf("%s%d%d",op,&a,&b);
76             if(op[0]==‘U‘){
77                 d[++a]=b;
78                 update(a,1,n,1);
79             }
80             if(op[0]==‘Q‘){
81
82                 printf("%d\n",query(a+1,b+1,1,n,1));
83             }
84         }
85     }
86     return 0;
87 }
时间: 2024-10-11 18:10:54

HDU3308 LCIS的相关文章

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

题目链接 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[]

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的区间最长子序列当然就是自己,对于两个区间的最长子序列合并,无非就是两种情况,一种就是两个区间的最长子序列接上了,第二种就是没接上,取两个最长

线段树题目总结

一.单点更新 1.hdu1166 敌兵布阵:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)"Addij",表示第i个营地增加j人.(2)"Sub i j",表示第i个营地减少j人.(3)"Query ij",查询第i个营地到第j个营地的总人数.(4)"End",表示命令结束.解题报告Here. 2.hdu1754 I Hate It:给你N个数,M个操作,操作分两类.(1)"QAB"

数据结构---线段树

线段树 转载请注明出处,谢谢!http://blog.csdn.net/metalseed/article/details/8039326  持续更新中···   一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树

(转载)线段树模板(来自胡浩大牛)

http://www.notonlysuccess.com/(今天看二叉树,想回来看看,发现大牛博客进不去...) 如果要学,就要好好学.我copy的,如有错,请看http://www.cnblogs.com/Mu-Tou/archive/2011/08/11/2134427.html [完全版]线段树 很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章了,觉得当时的代码风格实在是太丑了,很多线段树的初学者

线段树完全版【代码集合

可能有些题要重写,先放这么多 单点更新 1.hdu1166敌兵布阵 1 #include <stdio.h> 2 #define maxn 200000 3 #include <algorithm> 4 using namespace std; 5 int qr, ql, v, x, l, n, ans; 6 int tree[maxn]; 7 void build(int o, int l,int r) { 8 if (l == r) { 9 scanf("%d&quo

线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnlySuccess的博文“完全版线段树”里的大部分题目,其博文地址Here,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放