HDU - 3308 LCIS (线段树 单点更新 区间查询)
2017-06-06 22:29
369 查看
hdu 3308 http://acm.hdu.edu.cn/showproblem.php?pid=3308
题意:要维护最长连续子序列
思路:区间查询,需要知道每段的前缀最大lcis,后缀lcis,每次用子节点来更新父节点的值的时候就要比较左右结点的后缀和前缀能否相连,左节点的lcis,右结点的lcis,这中间最长的就是父节点的lcis。
这两天深刻让我认识到了我的线段数和别人的线段树的差别。我的线段树真的写的丑死了…而且我的查询函数写的真的是。。。
这题是寒假拉过的题,然而当时不会写,今天总算是写出来了,不知道寒假的我写线段树的时候写的是些什么鬼。
代码:
//未参考他人query函数前自己写的。
//参考代码改之后的query函数
可以看出来多想一点会让代码更加清晰与精简
题意:要维护最长连续子序列
思路:区间查询,需要知道每段的前缀最大lcis,后缀lcis,每次用子节点来更新父节点的值的时候就要比较左右结点的后缀和前缀能否相连,左节点的lcis,右结点的lcis,这中间最长的就是父节点的lcis。
这两天深刻让我认识到了我的线段数和别人的线段树的差别。我的线段树真的写的丑死了…而且我的查询函数写的真的是。。。
这题是寒假拉过的题,然而当时不会写,今天总算是写出来了,不知道寒假的我写线段树的时候写的是些什么鬼。
代码:
//未参考他人query函数前自己写的。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define l(s) tr[s].l #define r(s) tr[s].r const int maxn = 1e5+10; int d[maxn]; struct node { int l,r,v,b,e; }tr[maxn<<2]; void reset(int l,int r,int id) { tr[id].l = l; tr[id].r = r; tr[id].v = tr[id].b = tr[id].e = 0; } int len(int id) { return tr[id].r-tr[id].l+1; } int useson(int id) { int l = tr[id].l, r = tr[id].r; int mid = l+r>>1; int res = 0; if(d[mid] < d[mid+1]) res = tr[id<<1].e + tr[id<<1|1].b; if(tr[id<<1].b == len(id<<1) && d[mid] < d[mid+1]) tr[id].b = tr[id<<1].b + tr[id<<1|1].b; else tr[id].b = tr[id<<1].b; if(tr[id<<1|1].e == len(id<<1|1) && d[mid] < d[mid+1]) tr[id].e = tr[id<<1].e + tr[id<<1|1].e; else tr[id].e = tr[id<<1|1].e; tr[id].v = max(res,tr[id<<1].v); tr[id].v = max(tr[id].v,tr[id<<1|1].v); return 0; } void build(int l,int r,int id) { reset(l,r,id); if(l == r) { tr[id].v = tr[id].b = tr[id].e = 1; return;} int mid = l+r>>1; build(l,mid,id<<1); build(mid+1,r,id<<1|1); useson(id); } int add(int x,int v,int id) { int l = tr[id].l, r = tr[id].r; if(x < l || x > r) return 0; if(x == l && r == l)return 0; int mid = l+r>>1; if(x <= mid) add(x,v,id<<1); if(x > mid) add(x,v,id<<1|1); useson(id); } node query(int ql,int qr,int id) { int l = tr[id].l, r = tr[id].r; if(l == ql && qr == r) return tr[id]; node ans; int mid = l+r>>1; if(qr <= mid) ans = query(ql,qr,id<<1); else if(ql > mid) ans = query(ql,qr,id<<1|1); else { node anl = query(ql,mid,id<<1); node anr = query(mid+1,qr,id<<1|1); if(d[mid] < d[mid+1]) ans.v = anl.e + anr.b; ans.v = max(ans.v,anl.v); ans.v = max(ans.v,anr.v); if(anl.b == anl.r-anl.l+1 && d[mid] < d[mid+1]) ans.b = anl.b + anr.b; else ans.b = anl.b; if(anr.e == anr.r-anr.l+1 && d[mid] < d[mid+1]) ans.e = anl.e + anr.e; else ans.e = anr.e; } return ans; } int main() { int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) scanf("%d",&d[i]); build(1,n,1); for(int i = 0; i < m ; i++) { char s[3]; int a,b; scanf("%s%d%d",s,&a,&b); if(s[0] == 'U') { d[++a] = b; add(a,b,1); } else { node ans = query(a+1,b+1,1); printf("%d\n",ans.v); } } } return 0; }
//参考代码改之后的query函数
可以看出来多想一点会让代码更加清晰与精简
int query(int ql,int qr,int id) { int l = tr[id].l, r = tr[id].r; if(l >= ql && qr >= r) return tr[id].v; if(r < ql || l > qr ) return 0; int ans = 0; int mid = l+r>>1; if(qr <= mid) ans = query(ql,qr,id<<1); else if(ql > mid) ans = query(ql,qr,id<<1|1); else { int ll = query(ql,mid,id<<1); int rr = query(mid+1,qr,id<<1|1); ans = max(ll,rr); if(d[mid] < d[mid+1]) ans = max(ans, min(mid-ql+1,tr[id<<1].e) + min(qr-mid,tr[id<<1|1].b)); } return ans; }
相关文章推荐
- HDU 3308 LCIS(线段树单点更新区间合并)
- HDU 3308 线段树 最长连续上升子序列 单点更新 区间查询
- HDU 3308 线段树 最长连续上升子序列 单点更新 区间查询
- hdu 3308 LCIS(线段树单点更新+区间合并)中等难度的题目
- hdu 3308 线段树 区间合并+单点更新+区间查询
- hdu 3308 LCIS (线段树+单点更新+区间合并)
- HDU 3308 LCIS(线段树区间合并 单点更新)
- 【HDU - 3308】 LCIS 【线段树+单点更新+区间合并】
- HDU 4819:单点更新,区间查询的二维线段树
- hdu 4893 Wow! Such Sequence! 线段树单点更新+区间更新+区间查询
- hdu 3308 LCIS(单点更新+区间合并)
- hdu 3308 LCIS (线段树单点更新)
- HDU 3308 LCIS (线段树·单点更新·区间合并)
- HDU 3308 LCIS(区间合并 + 单点更新)
- hdu 1540 Tunnel Warfare 线段树 单点更新,查询区间长度,区间合并
- HDU 3308 LCIS(线段树:单点更新,求最大连续子串)
- HDU 1540——Tunnel Warfare(线段树,区间合并+单点更新+单点查询)
- HDU 3874 Necklace (线段树单点更新+区间查询+离线操作)
- HDU 3308 LCIS 线段树区间更新
- HDU 1754 多个学生偷改成绩问最高分-线段树-(单点更新,区间查询)