题目传送: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; }
HDU - 3308 - LCIS (线段树 - 区间合并)
原文地址:http://blog.csdn.net/u014355480/article/details/45749241