LCIS线段树(区间更新)

首先线段树每一个节点包含:[b,e],lmax,rmax,max;其中lmax表示从左端点开始连续的最长的增序列长度,rmax表示从e端点开始向左连续的最长下降序列长度,max表示当前区间的连续递增的最长序列长度。对单个节点插入时的信息维护如下:

(1) if 左儿子的右端点的值<右儿子的左端点的值

lmax=左儿子区间长度==左儿子的lmax?左儿子区间长度+右儿子的lmax:左儿子的lmax.

rmax=右儿子区间长度==右儿子的rmax?右儿子区间长度+左儿子的rmax:右儿子的rmax.

max=MAX(lmax,rmax,左儿子的rmax+右儿子的lmax);

(2)否则

lmax=左儿子的lmax;

rmax=右儿子的rmax;

max=MAX(左儿子的max,右儿子的max);

查寻操作如下:

if 当前节点区间==查询区间

返回当前节点的max

否则

返回 MAX(左区间,右区间,跨越边界的长度)

//------------------------------------------------------------------
//---线段树区间更新
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1000000;
struct Tnode{
	int b, e;
	int lmax;
	int rmax;
	int max;
	int len(){ return e - b + 1; }
};
Tnode tree[4*MAXN];
int p[MAXN];
int n, m;
int max(int a, int b, int c){
	return max(max(a, b), c);
}
void Build(int v, int l, int r){
	tree[v].b = l, tree[v].e = r;
	tree[v].lmax = tree[v].rmax = tree[v].max = 0;
	if (l < r){
		int mid = (l + r) >> 1;
		Build(2 * v + 1, l, mid);
		Build(2 * v + 2, mid + 1, r);
	}
}
void Insert(int v, int k, int val){
	if (tree[v].b == tree[v].e){
		//找到叶节点插入
		p[k] = val;
		tree[v].lmax = tree[v].rmax = tree[v].max = 1;
		return;
	}
	int mid = (tree[v].b + tree[v].e) >> 1;
	if (k <= mid)
		Insert(2 * v + 1, k, val);
	else
		Insert(2 * v + 2, k, val);
	//接下来更新
	if (p[mid] < p[mid + 1]){
		if (tree[2 * v + 1].lmax == tree[2 * v + 1].len())
			tree[v].lmax = tree[2 * v + 1].len() + tree[2 * v + 2].lmax;
		else
			tree[v].lmax = tree[2*v+1].lmax;

		if (tree[2 * v + 2].rmax == tree[2 * v + 2].len())
			tree[v].rmax = tree[2 * v + 2].len() + tree[2 * v + 1].rmax;
		else
			tree[v].rmax = tree[2*v+2].rmax;
		tree[v].max = max(tree[2 * v + 1].max, tree[2 * v + 2].max,tree[2 * v + 1].rmax + tree[2 * v + 2].lmax);
	}
	else{
		tree[v].lmax = tree[2*v+1].lmax;
		tree[v].rmax = tree[2 * v + 2].rmax;
		tree[v].max = max(tree[2 * v + 1].max,tree[2 * v + 2].max);
	}
}
int Qurrey(int v,int l, int r){
	if (l == tree[v].b&&r == tree[v].e)
		return tree[v].max;
	int mid = (tree[v].b + tree[v].e) >> 1;
	if (r <= mid)
		return Qurrey(2 * v + 1, l, r);
	else if (l > mid)
		return Qurrey(2 * v + 2, l, r);
	else{
		if (p[mid] < p[mid + 1]){
			int left = max(mid + 1 - tree[2 * v + 1].rmax, l);
			int right = min(r, mid + tree[2 * v + 2].lmax);
			return max(Qurrey(2 * v + 1, l, mid), Qurrey(2 * v + 2, mid + 1, r), right-left+1);
		}
		else
			return  max(Qurrey(2 * v + 1, l, mid), Qurrey(2 * v + 2, mid + 1, r));
	}
}
int main(){
	int i, T,a,b;
	char s;
	scanf("%d", &T);
	while (T--){
		scanf("%d%d", &n, &m);
		memset(p, 0, sizeof(p));
		Build(0, 0, n - 1);
		for (i = 0; i < n; i++){
			scanf("%d", &p[i]);
			Insert(0, i, p[i]);
		}
		while (m--){
			cin >> s;
			scanf("%d%d",&a, &b);
			if (s == ‘U‘)
				Insert(0, a, b);
			else
				printf("%d\n", Qurrey(0, a, b));
		}
	}
	return 0;
}

  

时间: 2024-10-24 20:48:05

LCIS线段树(区间更新)的相关文章

HDU 3308 LCIS 线段树 区间更新

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目描述: 有两种操作, U x y  , 第xth赋值为y .Q x y , 查询区间x-y的最长连续上升子序列的长度L 解题思路: 对于线段树不好的我依然好难.....有太多细节需要注意了....但是这是一道很好的题, 一段区间的L可能从三个地方来, 一种是中间, 一种是以左起点为开头的, 一种是以右起点结尾的, 这样查询的时候就要注意了: 如果两段的中间值是a[m] < a[m+1]

HDU 1689 Just a Hook 线段树区间更新求和

点击打开链接 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18894    Accepted Submission(s): 9483 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible

POJ 2528 Mayor&#39;s posters (线段树区间更新+离散化)

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

HDU 5023 A Corrupt Mayor&#39;s Performance Art 线段树区间更新+状态压缩

Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5023 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <string> 7 #include <cmath> 8 using namesp

hihocoder 1080 线段树(区间更新)

题目链接:http://hihocoder.com/problemset/problem/1080 , 两种操作的线段树(区间更新). 这道题前一段时间一直卡着我,当时也是基础不扎实做不出来,今天又想了想其实还是比较简单的,也只能怪自己太弱了. 这道题坑就坑在是有两个操作:set和add,所以lazy标记数组就需要两个,但是有一点要考虑的是一个区间上set与add的先后关系——如果对于一个区间set和add标记同时存在,那么应该如果处理:一种情况set在add之前,那么就按照正常顺序来就可以了:

(简单) POJ 3468 A Simple Problem with Integers , 线段树+区间更新。

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. 题意

HDU 5023 A Corrupt Mayor&#39;s Performance Art(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 解题报告:一面墙长度为n,有N个单元,每个单元编号从1到n,墙的初始的颜色是2,一共有30种颜色,有两种操作: P a b c  把区间a到b涂成c颜色 Q a b 查询区间a到b的颜色 线段树区间更新,每个节点保存的信息有,存储颜色的c,30种颜色可以压缩到一个int型里面存储,然后还有一个tot,表示这个区间一共有多少种颜色. 对于P操作,依次往下寻找,找要更新的区间,找到要更新的区间之前

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d