HDU - 3308 - LCIS (线段树 - 区间合并)


题目传送:LCIS


线段树,区间合并,一次过啦,没有纠结,这几天过的最愉快的一个题

思路:求最长连续上升子序列,外带单点更新,经典的线段树题目。具体看代码注释


AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <deque>
#include <cctype>
#define LL long long
#define INF 0x7fffffff
using namespace std;

int n, m;
const int maxn = 100005;

struct node {
	int sub;//表示当前结点最长连续上升子序列 
	int lsub;//表示以最左边为开始的最长连续上升子序列 
	int rsub;//表示以最右边为结束的最长连续上升子序列 
	int l, r;//表示当前结点(一段区间)的最左位置的值和最右位置的值 
}e[maxn << 2];

void pushup(int rt, int m) {//往上更新,略复杂 
	e[rt].l = e[rt << 1].l;//更新最左 
	e[rt].r = e[rt << 1 | 1].r;//更新最右 
	e[rt].sub = max(e[rt << 1].sub, e[rt << 1 | 1].sub);//更新当前结点最长连续上升子序列
	if(e[rt << 1 | 1].l > e[rt << 1].r) 
		e[rt].sub = max(e[rt].sub, e[rt << 1].rsub + e[rt << 1 | 1].lsub);
	
	e[rt].lsub = e[rt << 1].lsub;//更新以最左边为开始的最长连续上升子序列  
	if(e[rt].lsub == m - (m >> 1) && e[rt << 1].r < e[rt << 1 | 1].l) 
		e[rt].lsub += e[rt << 1 | 1].lsub; 
	
	e[rt].rsub = e[rt << 1 | 1].rsub;//更新以最右边为结束的最长连续上升子序列  
	if(e[rt].rsub == (m >> 1) && e[rt << 1].r < e[rt << 1 | 1].l) 
		e[rt].rsub += e[rt << 1].rsub; 
}

void build(int l, int r, int rt) {//建树 
	if(l == r) {
		int t;
		scanf("%d", &t);
		e[rt].l = e[rt].r = t;
		e[rt].sub = e[rt].lsub = e[rt].rsub = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, rt << 1);
	build(mid + 1, r, rt << 1 | 1);
	pushup(rt, r - l + 1);
}

int query(int L, int R, int l, int r, int rt) {//查询 
	if(L <= l && r <= R) {
		return e[rt].sub;
	}
	int ret = 0;
	int mid = (l + r) >> 1;
	if(L <= mid) ret = max(ret, query(L, R, l, mid, rt << 1));
	if(mid < R) ret = max(ret, query(L, R, mid + 1, r, rt << 1 | 1));
	if(e[rt << 1].r < e[rt << 1 | 1].l && mid >= L && mid < R)//关键,看是否取中间的连续上升子序列  
		ret = max(ret, min(e[rt << 1].rsub, mid - L + 1) + min(e[rt << 1 | 1].lsub, R - mid));
	return ret;
}

void update(int p, int x, int l, int r, int rt) {//更新 
	if(l == r) {
		e[rt].l = e[rt].r = x;
		return;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) update(p, x, l, mid, rt << 1);
	else update(p, x, mid + 1, r, rt << 1 | 1);
	pushup(rt, r - l + 1);
}

int main() {
	int T;
	scanf("%d", &T);
	while(T --) {
		scanf("%d %d", &n, &m);
		build(0, n - 1, 1);
		char op[5];
		int a, b;
		while(m --) {
			scanf("%s %d %d", op, &a, &b);
			if(op[0] == 'Q') {
				printf("%d\n", query(a, b, 0, n - 1, 1));
			}
			else if(op[0] == 'U') {
				update(a, b, 0, n - 1, 1);
			}
		}
	}
	return 0;
}







你可能感兴趣的:(线段树,ACM,HDU,区间的维护和更新)