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 < ...
随机推荐
- Unity 中动态修改碰撞框(位置,大小,方向)
在Unity中,玩家处于不同的状态,要求的碰撞框的 位置/大小/方向 会有所改变,怎么动态的修改碰撞框呢? 下面是Capsure Collider(胶囊体)的修改: CapsuleCollider.d ...
- 如何在MySQL中设置外键约束
引用:http://blog.sina.com.cn/s/blog_53729e4601011wja.html MySql外键设置详解 (1) 外键的使用: 外键的作用,主要有两个: 一个是 ...
- 飘逸的python - @staticmethod和@classmethod的作用与区别
一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法. 而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用. 这有利于组织代码,把某些应 ...
- 2017-10-24 NOIP模拟赛
括号序列 (bracket) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一个括号序列,但这个序列不一定合法. 一个合法的括号序列如下: ()是合法 ...
- bzoj1934: [Shoi2007]Vote 善意的投票(最小割)
传送门 考虑源点为同意,汇点为反对,那么只要源点向同意的连边,不同意的向汇点连边,求个最小割就是答案 然后考虑朋友之间怎么办,我们令朋友之间连双向边.这样不管怎么割都能对应一种选择情况.那么还是求一个 ...
- Exadata中Infiniband交换机升级
Infiniband交换机的软件补丁包,随着软件版本的不同,其发布方式也有所变化,从如下图表可以看出,1.3.3-2这个版本是一个分水岭,这个版本及以前的版本,补丁包是单独下载的,而之后的版本,inf ...
- c语言中malloc函数的使用
传送门:https://www.cnblogs.com/shiweihappy/p/4246372.html c语言中内存的管理:https://www.cnblogs.com/tuhooo/p/72 ...
- springboot 简单使用shiro登录
首先引入需要的pom <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shir ...
- LeetCode初级算法(数组)解答
这里记录了LeetCode初级算法中数组的一些题目: 加一 本来想先转成整数,加1后再转回去:耽美想到测试的例子考虑到了这个方法的笨重,所以int类型超了最大范围65536,导致程序出错. class ...
- vue——做了一个幼稚的小页面
我的小花花没有转起来,不开心  ̄へ ̄