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[]
3)整个区间的最长连续递增子序列长度,记作sub[]
每次pushUp都需要自下而上更新这三个值。
注意点:
对于左连续,既可以由左儿子的左连续得来,也可能包含右儿子的左连续,这就要判断左儿子的左连续是否覆盖了整个区间,并且左儿子的最右值小于右儿子的最左值。同理对于右连续也是一样的。
对于整个区间的LCIS,可能来源于左右儿子的最值(因为可能左儿子的最右值不小于右儿子的最左值),也可能来源于两个区间的中间部分。
代码

  1 #include<stdio.h>
  2 const int maxn = 100010;
  3 int n, m, x, y;
  4 char ch[5];
  5 int val[maxn], sub[maxn * 4], pre[maxn * 4], suf[maxn * 4];
  6
  7 int max(int a, int b)
  8 {
  9     return a > b ? a : b;
 10 }
 11 int min(int a, int b)
 12 {
 13     return a < b ? a : b;
 14 }
 15
 16 void pushUp(int rt, int l, int r)
 17 {
 18     int m = (l + r) / 2;
 19
 20     sub[rt] = max(sub[rt * 2], sub[rt * 2 + 1]);
 21     if(val[m] < val[m + 1])
 22         sub[rt] = max(sub[rt], suf[rt * 2] + pre[rt * 2 + 1]);
 23
 24     pre[rt] = pre[rt * 2];
 25     if(pre[rt] == m - l + 1 && val[m] < val[m + 1])
 26         pre[rt] += pre[rt * 2 + 1];
 27
 28     suf[rt] = suf[rt * 2 + 1];
 29     if(suf[rt] == r - m && val[m] < val[m + 1])
 30         suf[rt] += suf[rt * 2];
 31 }
 32
 33 void build(int rt, int l, int r)
 34 {
 35     if(l == r)
 36     {
 37         sub[rt] = pre[rt] = suf[rt] = 1;
 38         return;
 39     }
 40     int m = (l + r) / 2;
 41     build(rt * 2, l, m);
 42     build(rt * 2 + 1, m + 1, r);
 43     pushUp(rt, l, r);
 44 }
 45
 46 void update(int rt, int l, int r)
 47 {
 48     if(l == r)
 49         return;
 50     int m = (l + r) / 2;
 51     if(x <= m)
 52         update(rt * 2, l, m);
 53     else
 54         update(rt * 2 + 1, m + 1, r);
 55     pushUp(rt, l, r);
 56 }
 57
 58 int query(int rt, int l, int r)
 59 {
 60     if(x <= l && y >= r)
 61         return sub[rt];
 62     int m = (l + r) / 2;
 63     if(y <= m)
 64         return query(rt * 2, l, m);
 65     if(x > m)
 66         return query(rt * 2 + 1, m + 1, r);
 67     int ans = max(query(rt * 2, l, m), query(rt * 2 + 1, m + 1, r));
 68     if(val[m] < val[m + 1])
 69     {
 70         ans = max(ans, min(suf[rt * 2], m - x + 1) + min(pre[rt * 2 + 1], y - m));
 71     }
 72     return ans;
 73 }
 74 int main()
 75 {
 76     int t;
 77     scanf("%d", &t);
 78     while(t--)
 79     {
 80         scanf("%d%d", &n, &m);
 81         for(int i = 1; i <= n; i++)
 82             scanf("%d", &val[i]);
 83         build(1, 1, n);
 84         while(m--)
 85         {
 86             scanf("%s%d%d", ch, &x, &y);
 87             x += 1;    //下标:0 1
 88             if(ch[0] == ‘U‘)
 89             {
 90                 val[x] = y;
 91                 update(1, 1, n);
 92             }
 93             else if(ch[0] == ‘Q‘)
 94             {
 95                 y += 1;
 96                 printf("%d\n", query(1, 1, n));
 97             }
 98         }
 99     }
100     return 0;
101 }

原文地址:https://www.cnblogs.com/friend-A/p/10011356.html

时间: 2024-10-19 01:03:42

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

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

线段树题目总结

一.单点更新 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,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放