题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 ,简单的线段树区间合并。

  线段树的区间合并:一般是要求求最长连续区间,在PushUp()函数中实现区间合并操作。


解法:

  由于对于一个区间的最长序列来说,最优解要么完全在左半序列,要么完全在右半序列,要么跨越中间点。所以可以构造线段树,维护结点区间的三个元素:最长上升前缀len[].l,最长上升后缀len[].r,最长上升序列len[].m。所以对于一个区间来说,有这样两种情况:

1. 左儿子最右边的值 >= 右儿子最左边的值(不能区间合并)

  前缀 = 左儿子的前缀    len[rt].l = len[rt << 1].l

  后缀 = 右儿子的后缀    len[rt].r = len[rt << 1 | 1].r

  最长序列 = 左右儿子的最长序列的最大值    len[rt].m = max(len[rt << 1].m , len[rt << 1 | 1].m)

2. 左儿子最右边的值 < 右儿子最左边的值(可以区间合并)

  前缀 = (左儿子的前缀 == 左儿子的长度) ? 左儿子的前缀 + 右儿子的前缀 : 左儿子的前缀

  后缀 = (右儿子的后缀 == 右儿子的长度) ? 右儿子的后缀 + 左儿子的后缀 : 右儿子的后缀

  最长序列 = max(左儿子的后缀 + 右儿子的前缀 , 左儿子的最长序列, 右儿子的最长序列)

  

  还有要注意的是query()函数,在查询的时候,完全在区间左半边或者完全在区间右半边的情况比较好办,如果是两边都有的话这样来考虑:

1.区间不能合并:这种情况可以直接返回左右儿子查询的最大值即可;

2.区间可以合并:左右儿子合并后的长度、左右儿子的查询,这三者取最大值;这里要注意合并左右儿子的时候不能超过查询区间的长度。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define flag a[m + 1] > a[m] //区间合并的标志
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = + ;
struct Max_len { //三个元素
int l , r , m;
} len[maxn << ];
int a[maxn]; void PushUp(int l , int r , int rt)
{   //在PushUp中实现区间合并
int m = (l + r) >> ;
len[rt].l = len[rt << ].l;
if(flag && len[rt].l == (m - l + ))
len[rt].l += len[rt << | ].l; len[rt].r = len[rt << | ].r;
if(flag && len[rt].r == (r - m))
len[rt].r += len[rt << ].r; if(flag) {
len[rt].m = max(len[rt << ].r + len[rt << | ].l ,
max(len[rt << ].m , len[rt << | ].m));
} else {
len[rt].m = max(len[rt << ].m , len[rt << | ].m);
}
}
void build(int l , int r , int rt)
{
if(l == r) {
scanf("%d" , &a[l]);
len[rt].l = len[rt].r = len[rt].m = ;
return;
}
int m = (l + r) >> ;
build(lson);
build(rson);
PushUp(l , r , rt);
}
void update(int p , int x , int l , int r , int rt)
{
if(l == r) {
a[p] = x;
return;
}
int m = (l + r) >> ;
if(p <= m)
update(p , x , lson);
else
update(p , x , 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].m;
}
int m = (l + r) >> ;
if(R <= m)
return query(L , R , lson);
else if(L > m)
return query(L , R , rson);
else {
int ll = query(L , R , lson);
int rr = query(L , R , rson);
int ret = max(ll , rr);
if(flag) {
ll = min(len[rt << ].r , m - L + ); //不能超过查询区间的长度
rr = min(len[rt << | ].l , R - m);
ret = max(ret , ll + rr);
}
return ret;
}
}
int main()
{
int n , m , T;
int a , b;
char ch[];
cin >> T;
while(T--) {
scanf("%d %d" , &n , &m);
build( , n - , );
while(m--) {
scanf("%s" , ch);
if(ch[] == 'U') {
scanf("%d %d" , &a , &b);
update(a , b , , n - , );
} else {
scanf("%d %d" , &a , &b);
printf("%d\n" , query(a , b , , n - , ));
}
}
}
return ;
}

 

HDU3308 线段树区间合并的更多相关文章

  1. LCIS hdu3308 (线段树 区间合并)

    题意: 有两种操作  一种是单点改为b  一种是给出区间ab  区间ab的最大上升子序列个数.. 线段树目前学了三种  第一种单点操作很简单   第二种区域操作加上懒惰标记即可 现在这种 为区间合并. ...

  2. hdu3308 线段树——区间合并

    更新一个点: 求某个区间的最长连续上升序列: 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 #include <cstdio> #in ...

  3. hdu3308 线段树 区间合并

    给n个数字 U表示第A个数改为B.A是从0开始. Q输出最大的递增序列个数. 考虑左边,右边,和最大的. #include<stdio.h> #define lson l,m,rt< ...

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

    LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  5. POJ 3667 Hotel(线段树 区间合并)

    Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...

  6. HDU 3911 线段树区间合并、异或取反操作

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911 线段树区间合并的题目,解释一下代码中声明数组的作用: m1是区间内连续1的最长长度,m0是区间内连续 ...

  7. HDU 3911 Black And White(线段树区间合并+lazy操作)

    开始以为是水题,结果...... 给你一些只有两种颜色的石头,0为白色,1为黑色. 然后两个操作: 1 l r 将[ l , r ]内的颜色取反 0 l r 计算[ l , r ]内最长连续黑色石头的 ...

  8. HYSBZ 1858 线段树 区间合并

    //Accepted 14560 KB 1532 ms //线段树 区间合并 /* 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[ ...

  9. poj3667 线段树 区间合并

    //Accepted 3728 KB 1079 ms //线段树 区间合并 #include <cstdio> #include <cstring> #include < ...

随机推荐

  1. Java Script 学习笔记 -- jQuery

    一 jquery简介 1 jquery是什么  jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多 javascript高手加入其team. jQuery是继prototyp ...

  2. Ruby and gnuplot installation on Ubuntu 16.04

    sudo apt install ruby gnuplot

  3. linux线程私有数据---TSD池

    进程内的所有线程共享进程的数据空间,所以全局变量为所有线程共有.在某些场景下,线程需要保存自己的私有数据,这时可以创建线程私有数据(Thread-specific Data)TSD来解决.在线程内部, ...

  4. bzoj2502: 清理雪道(有源汇有上下界最小流)

    传送门 别说话,自己看,我不会->这里 我这里用的建图方法是先跑一次最大流,连上$(t,s,inf)$之后再跑一遍,然后答案就是之前连的那条边的反向边的流量 据说还有种方法是连上$(t,s,in ...

  5. [Xcode 实际操作]四、常用控件-(4)UILabel文本标签的自动换行

    目录:[Swift]Xcode实际操作 本文将演示标签控件的换行功能, 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class Vie ...

  6. Python中list作为默认参数的陷阱

    在Python中,作为默认参数的一定要是不可变对象,如果是可变对象,就会出现问题,稍不注意,就会调入陷阱,尤其是初学者,比如我(┬_┬). 我们来看一个例子. def add(L=[]): L.app ...

  7. 算法学习分析-点分治 HDU 6269 Master of Subgraph

    首先给出定义 点分治是一种处理树上路径的工具 挂出一道题目来:Master of Subgraph 这道题目让你求所有联通子图加和所能产生数字,问你1到m之间,那些数字可以被产生 这道题目,假如我们利 ...

  8. git教程3-分支

    https://git-scm.com/book/zh/v1/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E7%AE%A1%E7%90%86 ...

  9. Swing实现canvas-nest.js 源码

    #### 说明 canvas-nest.js 源码 http://www.bubuko.com/infodetail-2237716.html 地址:https://gitee.com/dgwcode ...

  10. spark_spark连接hive config

    1 环境 hadoop2.7.3 apache-hive-2.1.1-bin spark-2.1.0-bin-hadoop2.6 jdk1.8 2 配置文件 在hive-site.xml中配置mysq ...