BZOJ 3173 [Tjoi2013] 最长上升子序列 解题报告
这个题感觉比较简单,但却比较容易想残。。
我不会用树状数组求这个原排列,于是我只好用线段树。。。毕竟 Gromah 果弱马。
我们可以直接依次求出原排列的元素,每次找到最小并且最靠右的那个元素,假设这是第 $i$ 次找的,那么这就是原排列的第 $i$ 项,然后我们就把这个元素删去(变成很大的数),再把这个数以左的数都加 1,进行下一轮。
然后就是裸的最长上升子序列啦~~~
时间复杂度 $O(n\log n)$,空间复杂度 $O(n)$。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 #define N 100000 + 5 5 #define M 262144 + 5 6 #define ls(x) x << 1 7 #define rs(x) x << 1 | 1 8 9 int n, Pos[N], A[N], T[N], F[N]; 10 11 struct Segment_Tree 12 { 13 int Min, delta; 14 }h[M]; 15 16 inline void Build(int x, int l, int r) 17 { 18 if (l == r) 19 { 20 h[x].Min = Pos[l]; 21 return ; 22 } 23 int mid = l + r >> 1; 24 Build(ls(x), l, mid); 25 Build(rs(x), mid + 1, r); 26 h[x].Min = min(h[ls(x)].Min, h[rs(x)].Min); 27 } 28 29 inline void apply(int x, int d) 30 { 31 h[x].Min += d, h[x].delta += d; 32 } 33 34 inline void push(int x) 35 { 36 if (h[x].delta) 37 { 38 apply(ls(x), h[x].delta); 39 apply(rs(x), h[x].delta); 40 h[x].delta = 0; 41 } 42 } 43 44 inline void Modify(int x, int l, int r, int s, int t, int d) 45 { 46 if (l == s && r == t) 47 { 48 apply(x, d); 49 return ; 50 } 51 push(x); 52 int mid = l + r >> 1; 53 if (t <= mid) Modify(ls(x), l, mid, s, t, d); 54 else if (s > mid) Modify(rs(x), mid + 1, r, s, t, d); 55 else Modify(ls(x), l, mid, s, mid, d), Modify(rs(x), mid + 1, r, mid + 1, t, d); 56 h[x].Min = min(h[ls(x)].Min, h[rs(x)].Min); 57 } 58 59 inline int Query(int x, int l, int r) 60 { 61 if (l == r) return l; 62 int mid = l + r >> 1; 63 if (h[rs(x)].Min <= h[ls(x)].Min) 64 return Query(rs(x), mid + 1, r); 65 else return Query(ls(x), l, mid); 66 } 67 68 int main() 69 { 70 #ifndef ONLINE_JUDGE 71 freopen("3173.in", "r", stdin); 72 freopen("3173.out", "w", stdout); 73 #endif 74 75 scanf("%d", &n); 76 for (int i = 1; i <= n; i ++) 77 scanf("%d", Pos + i); 78 Build(1, 1, n); 79 for (int i = 1; i <= n; i ++) 80 { 81 int t = Query(1, 1, n); 82 Modify(1, 1, n, 1, t, 1); 83 Modify(1, 1, n, t, t, n); 84 if (!T[0] || T[T[0]] < t) 85 { 86 T[++ T[0]] = t; 87 F[t] = T[0]; 88 } 89 else 90 { 91 int x = lower_bound(T + 1, T + T[0] + 1, t) - T; 92 T[x] = t; 93 F[t] = x; 94 } 95 } 96 for (int i = 1, Max = 0; i <= n; i ++) 97 { 98 Max = Max > F[i] ? Max : F[i]; 99 printf("%d\n", Max); 100 } 101 102 #ifndef ONLINE_JUDGE 103 fclose(stdin); 104 fclose(stdout); 105 #endif 106 return 0; 107 }