BZOJ 3173 [Tjoi2013] 最长上升子序列 解题报告
2015-06-25 21:44
567 查看
这个题感觉比较简单,但却比较容易想残。。
我不会用树状数组求这个原排列,于是我只好用线段树。。。毕竟 Gromah 果弱马。
我们可以直接依次求出原排列的元素,每次找到最小并且最靠右的那个元素,假设这是第 $i$ 次找的,那么这就是原排列的第 $i$ 项,然后我们就把这个元素删去(变成很大的数),再把这个数以左的数都加 1,进行下一轮。
然后就是裸的最长上升子序列啦~~~
时间复杂度 $O(n\log n)$,空间复杂度 $O(n)$。
3173_Gromah
我不会用树状数组求这个原排列,于是我只好用线段树。。。毕竟 Gromah 果弱马。
我们可以直接依次求出原排列的元素,每次找到最小并且最靠右的那个元素,假设这是第 $i$ 次找的,那么这就是原排列的第 $i$ 项,然后我们就把这个元素删去(变成很大的数),再把这个数以左的数都加 1,进行下一轮。
然后就是裸的最长上升子序列啦~~~
时间复杂度 $O(n\log n)$,空间复杂度 $O(n)$。
#include <cstdio> #include <algorithm> using namespace std; #define N 100000 + 5 #define M 262144 + 5 #define ls(x) x << 1 #define rs(x) x << 1 | 1 int n, Pos , A , T , F ; struct Segment_Tree { int Min, delta; }h[M]; inline void Build(int x, int l, int r) { if (l == r) { h[x].Min = Pos[l]; return ; } int mid = l + r >> 1; Build(ls(x), l, mid); Build(rs(x), mid + 1, r); h[x].Min = min(h[ls(x)].Min, h[rs(x)].Min); } inline void apply(int x, int d) { h[x].Min += d, h[x].delta += d; } inline void push(int x) { if (h[x].delta) { apply(ls(x), h[x].delta); apply(rs(x), h[x].delta); h[x].delta = 0; } } inline void Modify(int x, int l, int r, int s, int t, int d) { if (l == s && r == t) { apply(x, d); return ; } push(x); int mid = l + r >> 1; if (t <= mid) Modify(ls(x), l, mid, s, t, d); else if (s > mid) Modify(rs(x), mid + 1, r, s, t, d); else Modify(ls(x), l, mid, s, mid, d), Modify(rs(x), mid + 1, r, mid + 1, t, d); h[x].Min = min(h[ls(x)].Min, h[rs(x)].Min); } inline int Query(int x, int l, int r) { if (l == r) return l; int mid = l + r >> 1; if (h[rs(x)].Min <= h[ls(x)].Min) return Query(rs(x), mid + 1, r); else return Query(ls(x), l, mid); } int main() { #ifndef ONLINE_JUDGE freopen("3173.in", "r", stdin); freopen("3173.out", "w", stdout); #endif scanf("%d", &n); for (int i = 1; i <= n; i ++) scanf("%d", Pos + i); Build(1, 1, n); for (int i = 1; i <= n; i ++) { int t = Query(1, 1, n); Modify(1, 1, n, 1, t, 1); Modify(1, 1, n, t, t, n); if (!T[0] || T[T[0]] < t) { T[++ T[0]] = t; F[t] = T[0]; } else { int x = lower_bound(T + 1, T + T[0] + 1, t) - T; T[x] = t; F[t] = x; } } for (int i = 1, Max = 0; i <= n; i ++) { Max = Max > F[i] ? Max : F[i]; printf("%d\n", Max); } #ifndef ONLINE_JUDGE fclose(stdin); fclose(stdout); #endif return 0; }
3173_Gromah
相关文章推荐
- Ubuntu中Nginx的安装与配置
- Socket客户端与服务端
- 【进阶android】ListView源码分析——布局三大方法
- 按键码---VK_LEFT 0x4b00
- ffmpeg和Opencv结合进行视频解码播放
- Eclipse 代码提示功能失效问题解决
- Linux网络编程综合运用之MiniFtp实现(七)
- NPOI导出Excel(异步请求)
- JNI Kickstart 小结 02 :桥接至与 Java 无关的纯本地库
- 常用meta整理
- 带k最长上升子序列
- 并查集乱搞 bzoj1015
- [CSS]IE6和360浏览器兼容模式下的兼容性问题
- Python初始化实例属性
- code vs1099 字串变化 字符串搜索(STL)
- 模板方法模式分析、图表和基本代码
- 面试有感
- S01E22 Growing Pains
- 病人监护、胎儿监护(三参、九参)全套方案
- adt Failed to create the Java Virtual Machine.