首页 > 代码库 > 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 }
方法二:倒过来做,从最后开始一个个删,用树状数组维护,求序列的前缀第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 }
(p.s. 在我的各种读入/输出/常数优化后,终于成为rank.1 yeah!)
BZOJ3173 [Tjoi2013]最长上升子序列
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。