题目链接: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. Windows form UI skinEngine的使用方法

    1.安装SkinEngine(这里安装的是3.4.7) 链接: https://pan.baidu.com/s/1-kZ5KgYclshWc17jbuke5w 提取码: bp7n 复制这段内容后打开百 ...

  2. [CentOS7] firewalld重启失败 Failed to start firewalld - dynamic firewall daemon.

    错误信息: Failed to start firewalld - dynamic firewall daemon. 如图: 解决方法: 也就是kernel不支持现在的firewall防火墙的某些模块 ...

  3. oracle批量插入带主键自增

    https://blog.csdn.net/qq_37630354/article/details/82792288

  4. linux系统elementray os的环境搭建

    因为我在使用过程中为了改变终端的外表,结果把/ect/psswd,以及/ect/profile中的文件配置修改之后,我把gnome-terminal的python脚本打包放在/bin/目录下,修改了/ ...

  5. 51nod1035(循环节)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1035 题意:中文题诶- 思路:求满足 10^k=1(mod ...

  6. HyperLedger Explore 浏览器配置启动教程

    Hyperledger Fabric维护的实际上是一个区块链网络.为了能够直观的观察网络上的节点,交易等行为,Hyperledger Explore随之诞生. 本文讲述如何搭建 Hyperledger ...

  7. 洛谷P3147 [USACO16OPEN]262144

    P3147 [USACO16OPEN]262144 题目描述 Bessie likes downloading games to play on her cell phone, even though ...

  8. JavaWeb:Cookie处理和Session跟踪

    JavaWeb:Cookie处理和Session跟踪 Cookie处理 什么是Cookie Cookie 是存储在客户端计算机上的文本文件,保留了各种跟踪信息.因为HTTP协议是无状态的,即服务器不知 ...

  9. express-http-proxy 的基础使用

    const app = express() app.use(matchPath, proxy(serverAddress, { proxyReqPathResolver: function(req) ...

  10. .netcore中无法使用System.Drawing --解决方案

    问题重现: 无法正常使用  解决方法: 安装System.Drawing.Common的NuGet就能正常使用了 操作之后: 这个是.netcoe中的解决办法,.net framework解决方案中添 ...