标签:
题目链接: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 = 100000 + 5; struct Max_len { //三个元素 int l , r , m; } len[maxn << 2]; int a[maxn]; void PushUp(int l , int r , int rt) { //在PushUp中实现区间合并 int m = (l + r) >> 1; len[rt].l = len[rt << 1].l; if(flag && len[rt].l == (m - l + 1)) len[rt].l += len[rt << 1 | 1].l; len[rt].r = len[rt << 1 | 1].r; if(flag && len[rt].r == (r - m)) len[rt].r += len[rt << 1].r; if(flag) { len[rt].m = max(len[rt << 1].r + len[rt << 1 | 1].l , max(len[rt << 1].m , len[rt << 1 | 1].m)); } else { len[rt].m = max(len[rt << 1].m , len[rt << 1 | 1].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 = 1; return; } int m = (l + r) >> 1; 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) >> 1; 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) >> 1; 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 << 1].r , m - L + 1); //不能超过查询区间的长度 rr = min(len[rt << 1 | 1].l , R - m); ret = max(ret , ll + rr); } return ret; } } int main() { int n , m , T; int a , b; char ch[3]; cin >> T; while(T--) { scanf("%d %d" , &n , &m); build(0 , n - 1 , 1); while(m--) { scanf("%s" , ch); if(ch[0] == ‘U‘) { scanf("%d %d" , &a , &b); update(a , b , 0 , n - 1 , 1); } else { scanf("%d %d" , &a , &b); printf("%d\n" , query(a , b , 0 , n - 1 , 1)); } } } return 0; }
标签:
原文地址:http://www.cnblogs.com/H-Vking/p/4392533.html