hdu 3308 LCIS (线段树)
2010-09-22 11:48
295 查看
题意不难理解 就是求某一区间的最长连续递增子序列。
虽然猜测是线段树做法,但是之前没见过类似题目。 所以搜了下解题报告。
对于某一区间 ,我们保存以从该区最左边点为起点的最长子序列长度,和以该区间最右边的点为终点的最长子序列,以及该区间的最长子序列。
对于中点mid 如果a[mid]>=a[mid+1] 断开 那么有左边最长=左儿子左边最长 右边最长=右儿子右边最长 全局最长=Max(两个儿子的全局最长)
如果是连起来的a[mid]<a[mid+1] 那么在以上基础上更新 如果左边最长=左儿子长度(表示左半全不是最长递增子序列) 那么左边最长+=右儿子左边最长 同理如果右边最长=右儿子长度 那么右边最长+=左儿子右边最长
同时用左儿子右边最长+右儿子左边最长更新全局最长(中间连起来的)
最后查询的时候也有一点需要注意。
如果 对于某一区间 s<=mid &&e>mid 而且满足 a[mid]<a[mid+1]
中间长度并不是 左儿子右边最长+右儿子左边最长
该长度为 min(mid - s +1,tree[(i<<1)].mr) + min(e-mid,tree[(i<<1)|1].ml)
虽然猜测是线段树做法,但是之前没见过类似题目。 所以搜了下解题报告。
对于某一区间 ,我们保存以从该区最左边点为起点的最长子序列长度,和以该区间最右边的点为终点的最长子序列,以及该区间的最长子序列。
对于中点mid 如果a[mid]>=a[mid+1] 断开 那么有左边最长=左儿子左边最长 右边最长=右儿子右边最长 全局最长=Max(两个儿子的全局最长)
如果是连起来的a[mid]<a[mid+1] 那么在以上基础上更新 如果左边最长=左儿子长度(表示左半全不是最长递增子序列) 那么左边最长+=右儿子左边最长 同理如果右边最长=右儿子长度 那么右边最长+=左儿子右边最长
同时用左儿子右边最长+右儿子左边最长更新全局最长(中间连起来的)
最后查询的时候也有一点需要注意。
如果 对于某一区间 s<=mid &&e>mid 而且满足 a[mid]<a[mid+1]
中间长度并不是 左儿子右边最长+右儿子左边最长
该长度为 min(mid - s +1,tree[(i<<1)].mr) + min(e-mid,tree[(i<<1)|1].ml)
#include <cstdlib> #include <cstdio> #include <iostream> using namespace std; const int MAXN = 100000; struct node { int s; int e; int ml; int mr; int ma; } tree[MAXN * 4 + 10]; int num[MAXN + 10]; inline void update(int i) { int left = i << 1; int right = (i << 1) | 1; tree[i].ml = tree[left].ml; tree[i].mr = tree[right].mr; tree[i].ma = 0; int mid = (tree[i].s + tree[i].e) >> 1; if (num[mid] < num[mid + 1]) { if (tree[i].ml == tree[left].e - tree[left].s + 1) tree[i].ml += tree[right].ml; if (tree[i].mr == tree[right].e - tree[right].s + 1) tree[i].mr += tree[left].mr; tree[i].ma = tree[left].mr + tree[right].ml; } tree[i].ma = max(tree[i].ma, max(tree[left].ma, tree[right].ma)); } void init(int i, int s, int e) { tree[i].s = s; tree[i].e = e; if (s < e) { int mid = (s + e) >> 1; init(i << 1, s, mid); init((i << 1) | 1, mid + 1, e); update(i); } else { tree[i].ml = tree[i].mr = tree[i].ma = 1; } } void modify(int i, int s, int e, int val) { if (tree[i].s == s && tree[i].e == e) { num[tree[i].s] = val; } if (tree[i].s < tree[i].e) { int mid = (tree[i].s + tree[i].e) >> 1; if (e <= mid) modify(i << 1, s, e, val); else modify((i << 1) | 1, s, e, val); update(i); } return; } int query(int i, int s, int e) { if (tree[i].s == s && tree[i].e == e) { return tree[i].ma; } if (tree[i].s < tree[i].e) { int mid = (tree[i].s + tree[i].e) >> 1; if (e <= mid) return query(i << 1, s, e); else if (s > mid) return query((i << 1) | 1, s, e); else { if (num[mid] < num[mid + 1]) { int tmp = min(mid - s + 1, tree[i << 1].mr) + min(e - mid, tree[(i << 1) | 1].ml); return max(tmp, max(query(i << 1, s, mid), query((i << 1) + 1, mid + 1, e))); } return max(query(i << 1, s, mid), query((i << 1) + 1, mid + 1, e)); } } } int main(int argc, char** argv) { int T; scanf("%d", &T); while (T--) { int n, m; scanf("%d%d", &n, &m); int i(0); int tmp; for (i = 1; i <= n; ++i) { scanf("%d", num + i); } init(1, 1, n); char cmd[2]; int a, b; while (m--) { scanf("%s", cmd); if (cmd[0] == 'Q') { scanf("%d%d", &a, &b); printf("%d/n", query(1, a + 1, b + 1)); } else { scanf("%d%d", &a, &b); modify(1, a + 1, a + 1, b); } } } return 0; }
相关文章推荐
- (中等) 线段树 HDU 3308 LCIS
- hdu 3308 LCIS 线段树(单点更新)
- hdu 3308 LCIS(线段树区间合并)
- [HDU 3308]LCIS[线段树][区间合并]
- HDU 3308 LCIS 线段树 区间合并 入门题
- 【HDU - 3308】 LCIS 【线段树+单点更新+区间合并】
- 线段树(区间维护):HDU 3308 LCIS
- HDU-3308 LCIS 线段树 区间处理
- hdu 3308 LCIS (线段树)
- hdu 3308 LCIS (线段树单点更新)
- HDU 3308 LCIS(线段树)
- HDU 3308 LCIS(线段树,连续递增子)
- HDU 3308 LCIS 线段树的单点更新,区间合并
- HDU 3308 LCIS(线段树)
- HDU 3308 LCIS 线段树区间更新
- HDU - 3308 LCIS (线段树 单点更新 区间查询)
- HDU 3308 LCIS(线段树区间合并)
- HDU 3308 LCIS 线段树区间更新
- hdu 3308 LCIS(线段树,测试数据好坑!)
- HDU 3308 LCIS(线段树:单点更新,求最大连续子串)