HDU3308 线段树区间合并
题目链接: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 线段树区间合并的更多相关文章
- LCIS hdu3308 (线段树 区间合并)
题意: 有两种操作 一种是单点改为b 一种是给出区间ab 区间ab的最大上升子序列个数.. 线段树目前学了三种 第一种单点操作很简单 第二种区域操作加上懒惰标记即可 现在这种 为区间合并. ...
- hdu3308 线段树——区间合并
更新一个点: 求某个区间的最长连续上升序列: 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 #include <cstdio> #in ...
- hdu3308 线段树 区间合并
给n个数字 U表示第A个数改为B.A是从0开始. Q输出最大的递增序列个数. 考虑左边,右边,和最大的. #include<stdio.h> #define lson l,m,rt< ...
- hdu-3308 LCIS (线段树区间合并)
LCIS Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- POJ 3667 Hotel(线段树 区间合并)
Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...
- HDU 3911 线段树区间合并、异或取反操作
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911 线段树区间合并的题目,解释一下代码中声明数组的作用: m1是区间内连续1的最长长度,m0是区间内连续 ...
- HDU 3911 Black And White(线段树区间合并+lazy操作)
开始以为是水题,结果...... 给你一些只有两种颜色的石头,0为白色,1为黑色. 然后两个操作: 1 l r 将[ l , r ]内的颜色取反 0 l r 计算[ l , r ]内最长连续黑色石头的 ...
- HYSBZ 1858 线段树 区间合并
//Accepted 14560 KB 1532 ms //线段树 区间合并 /* 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[ ...
- poj3667 线段树 区间合并
//Accepted 3728 KB 1079 ms //线段树 区间合并 #include <cstdio> #include <cstring> #include < ...
随机推荐
- Protocol Buffers官方文档(开发指南)
本文是对官方文档的翻译,然后截取了一篇非常优秀的文章片段来帮助理解,本人英文水平有限,基本都是直译,如果有不理解的地方请参考英文官方文档,参考的文章链接在文章末尾 protocol buffers简介 ...
- 【leetcode 105. 从前序与中序遍历序列构造二叉树】解题报告
前往 中序,后序遍历构造二叉树, 中序,前序遍历构造二叉树 TreeNode* build(vector<int>& preorder, int l1, int r1, vecto ...
- Java中Object类的公有方法
HashCode();wait();notify();equals();getClass();toString();clone();finalize(); 这里只是简单介绍一下其中的几个函数: Has ...
- Ajax的完整兼容各种浏览器版本代码
<script type="text/javascript"> function createAjax(){ var request=false; //window对象 ...
- KSOAP2使用注意点汇总
注意返回类型,如果是XML格式,使用 1:SoapObject soapObject = (SoapObject) envelope.getResponse(); 2:SoapObject resul ...
- Oracle表连接(转)
表之间的连接 Join是一种试图将两个表结合在一起的谓词,一次只能连接2个表,表连接也可以被称为表关联.在后面的叙述中,我们将会使用”row source”来代替”表”,因为使用row source更 ...
- CF987C Three displays 解题报告
题目传送门 题目大意 n个位置,每个位置有两个属性s,c,要求选择3个位置i,j,k,使得s_i<s_j<s_k,并使得c_i+c_j+c_k最小 方法1 n³枚举每一种情况(也许可以拿 ...
- Git 2016视频教程
http://blog.csdn.net/biggbang/article/details/50830331
- 记录一个linux下批处理的代码
DATA_DIR=/home/liupan/.navinsight/data/dataset_rec SHELL_DIR=/home/liupan/workspace/nvi_postprocessi ...
- ForkJoin有参无返回值、有参有返回值实例
介绍: a . Fork/Join为JKD1.7引入,适用于对大量数据进行拆分成多个小任务进行计算的框架,最后把所有小任务的结果汇总合并得到最终的结果 b . 相关类 public abstract ...