首页 > 代码库 > BZOJ3173 [Tjoi2013]最长上升子序列

BZOJ3173 [Tjoi2013]最长上升子序列

可以称为,模拟题、、、

我们发现,由于是从小到大插入的,所以后插入的数不会影响先插入的数的ans

于是只要对最后的序列求一次LIS即可。

问题就集中在如何求最后的序列:

方法一:treap无脑模拟插入操作

就当是treap的练手吧。。。结果RE了一版,后来突然一拍脑袋发现。。bz上不让调用time()函数。。。各种蛋疼

 

技术分享
  1 /**************************************************************  2     Problem: 3173  3     User: rausen  4     Language: C++  5     Result: Accepted  6     Time:660 ms  7     Memory:3936 kb  8 ****************************************************************/  9   10 #include <cstdlib> 11 #include <cstdio> 12 #include <cstring> 13 #include <algorithm> 14   15 using namespace std; 16 const int N = 100005; 17 const int inf = 1e9; 18   19 struct treap_node { 20   treap_node *son[2]; 21   int pri, sz, v; 22 } *null, *root, mempool[N], *cnt_treap = mempool; 23   24 int n, cnt, len; 25 int a[N], ans[N], mn[N]; 26   27 int read() { 28   int x = 0; 29   char ch = getchar(); 30   while (ch < 0 || 9 < ch) 31     ch = getchar(); 32   while (0 <= ch && ch <= 9) 33     (x *= 10) += ch - 0, ch = getchar(); 34   return x; 35 } 36   37 #define Ls (p -> son[0]) 38 #define Rs (p -> son[1]) 39 #define Pri (p -> pri) 40 #define Sz (p -> sz) 41 #define V (p -> v) 42 inline void treap_update(treap_node *p) { 43   Sz = Ls -> sz + Rs -> sz + 1; 44 } 45   46 void treap_rotate(treap_node *&p, int ch) { 47   treap_node *tmp = p -> son[ch]; 48   p -> son[ch] = tmp -> son[!ch]; 49   tmp -> son[!ch] = p; 50   treap_update(p), treap_update(tmp); 51   p = tmp; 52 } 53   54 void treap_insert(treap_node *&p, int rank) { 55   if (p == null) { 56     p = ++cnt_treap, Ls = Rs = null; 57     Pri = rand(), Sz = 1, V = cnt; 58     return; 59   } 60   ++Sz; 61   if (Ls -> sz < rank) { 62     treap_insert(Rs, rank - Ls -> sz - 1); 63     if (Rs -> pri > Pri) treap_rotate(p, 1); 64   } else { 65     treap_insert(Ls, rank); 66     if (Ls -> pri > Pri) treap_rotate(p, 0); 67   } 68 } 69   70 void get_seq(treap_node *p) { 71   if (p == null) return; 72   get_seq(Ls); 73   a[++cnt] = V; 74   get_seq(Rs); 75 } 76 #undef Ls 77 #undef Rs 78 #undef Pri 79 #undef Sz 80 #undef Num 81   82 int main() { 83   int i, t; 84   n = read(); 85   null = ++cnt_treap; 86   null -> son[0] = null -> son[1] = null; 87   null -> pri = null -> sz = null -> v = 0; 88   root = null; 89   for (cnt = 1; cnt <= n; ++cnt) 90     treap_insert(root, read()); 91   cnt = 0; 92   get_seq(root); 93   memset(mn, 127, sizeof(mn)); 94   for (mn[0] = -inf, i = 1; i <= n; ++i) { 95     t = upper_bound(mn, mn + len + 1, a[i]) - mn; 96     if (mn[t - 1] <= a[i]) { 97       mn[t] = min(mn[t], a[i]); 98       ans[a[i]] = t; 99       len = max(t, len);100     }101   }102   for (i = 1; i <= n; ++i)103     printf("%d\n", ans[i] = max(ans[i], ans[i - 1]));104   return 0;105 }
View Code

方法二:倒过来做,从最后开始一个个删,用树状数组维护,求序列的前缀第k大

BIT的这种应用方式也是蛮神的。。。

 

技术分享
 1 /************************************************************** 2     Problem: 3173 3     User: rausen 4     Language: C++ 5     Result: Accepted 6     Time:248 ms 7     Memory:3540 kb 8 ****************************************************************/ 9  10 #include <cstdio>11 #include <cstring>12 #include <algorithm>13  14 #define lowbit(x) (x & -x)15 using namespace std;16 const int N = 100005;17 const int inf = 1e9;18 const int Maxlen = N * 8;19    20 int n, len;21 int a[N], ans[N], mn[N];22 int bit[N], b[N];23 char buf[Maxlen], *c = buf;24 int Len;25  26 inline int read() {27   int x = 0;28   while (*c < 0 || 9 < *c) ++c;29   while (0 <= *c && *c <= 9)30     x = x * 10 + *c - 0, ++c;31   return x;32 }33  34 void print(int x) {35   if (x >= 10) print(x / 10);36   putchar(x % 10 + 0);37 }38  39 inline int get_kth(int k) {40   int res = 0, cnt = 0, i;41   for (i = 20; ~i; --i) {42     res += 1 << i;43     if (res >= n || cnt + bit[res] >= k) res -= 1 << i;44     else cnt += bit[res];45   }46   return res + 1;47 }48  49 inline void bit_del(int x) {50   while (x <= n)51     --bit[x], x += lowbit(x);52 }53  54 int main() {55   Len = fread(c, 1, Maxlen, stdin);56   buf[Len] = \0;57   int i, t, w, mx;58   n = read();59   for (i = 1; i <= n; ++i) {60     b[i] = read(), ++bit[i];61     if (i + lowbit(i) <= n)62       bit[i + lowbit(i)] += bit[i];63   }64   for (i = n; i; --i) {65     a[w = get_kth(b[i] + 1)] = i;66     bit_del(w);67   }68   memset(mn, 127, sizeof(mn));69   for (mn[0] = -inf, i = 1; i <= n; ++i) {70     t = upper_bound(mn, mn + len + 1, a[i]) - mn;71     if (mn[t - 1] <= a[i]) {72       mn[t] = min(mn[t], a[i]);73       ans[a[i]] = t;74       len = max(t, len);75     }76   }77   for (i = 1, mx = 0; i <= n; ++i) {78     if (ans[i] > mx) mx = ans[i];79     print(mx);80     putchar(\n);81   }82   return 0;83 }
View Code

(p.s. 在我的各种读入/输出/常数优化后,终于成为rank.1 yeah!)

BZOJ3173 [Tjoi2013]最长上升子序列