题目链接: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. C#和Python 图片和base64的互转

    C#实例代码: /// <summary> /// 图片转base64 /// </summary> /// <param name="bmp"> ...

  2. AIM Tech Round 5 (rated, Div. 1 + Div. 2) E(思维,构造)

    #include<bits/stdc++.h>using namespace std;long long a[150007];long long ans[150007];int main( ...

  3. Unity应用的iOS热更新

    Unity应用的iOS热更新 作者:丁治宇 Unity TechnologiesChina Agenda •  什么是热更新 •  为何要热更新 •  如何在iOS 上对Unity 应用进行热更新 • ...

  4. 《OD学hadoop》20160903某旅游网项目实战

    一.大数据的落地点 1.数据出售 数据商城:以卖数据为公司的核心业务 2. 数据分析 百度统计 友盟 GA IBM analysis 3.搜索引擎 4. 推荐系统 mahout 百分比 5.精准营销 ...

  5. “戏精少女”的pandas学习之路,你该这么学!No.5

    如果文章图片无法观看,请前往CSDN博客观看 https://blog.csdn.net/hihell 戏精博主即将上线 就在上一篇,梦想橡皮擦这位博主经过艰苦的努力 终于能创建一个dataframe ...

  6. d190305面试题01总结

    题目一: 题目二: 题目三: 类中的某个成员变量可以被他和他的子类访问,应该用protected 知识点: 1.类中public修饰的属性,方法可以被该类,子孙类和外部类访问. 2.类中protect ...

  7. PAT甲级——1097 Deduplication on a Linked List (链表)

    本文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/91157982 1097 Deduplication on a L ...

  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. Python之PIP安装

    Python有两个著名的包管理工具easy_install.py和pip.Python2.7的安装包中自带了easy_install.py,而pip需要手动安装.而在Python3.5之后都是默认安装 ...

  10. 5、python数据类型之元组(tuple)

    元组 元组和列表最大的区别是元组中的元素固定,元组不能修改,所以不能对元组进行增.删.改 1.创建 tu = (11,22,33) tu = tuple(11,22,33) tu = tuple([] ...