hdu 3564 Another LIS (Splay Tree OR Segment Tree)
好不容易看见一道可以用Splay Tree写的题,结果应该是常数过大超时了。
好不容易还是给我找到bug了,就是一个字母打错,导致超时了。splay tree可以以421ms的时间完美通过。做法就是模拟插入数字,维护区间的最大LIS值即可。
Splay版代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 6 using namespace std; 7 8 const int inf = 0x77777777; 9 10 struct Node { 11 int data, cnt, max, val; 12 Node *c[2], *p; 13 Node(int data = 0, int val = 0, int cnt = 0) : data(data), val(val), cnt(cnt) { 14 c[0] = c[1] = p = NULL; 15 max = 0; 16 } 17 } *Null, *Root, *Head, *Tail; 18 19 void up(Node *x) { 20 Node *nl = x->c[0], *nr = x->c[1]; 21 x->max = max(nl->max, nr->max); 22 x->max = max(x->max, x->val); 23 x->cnt = nl->cnt + nr->cnt + 1; 24 } 25 26 void rotate(Node *x, bool right) { 27 Node *y = x->p; 28 bool left = !right; 29 y->c[left] = x->c[right]; 30 if (x->c[right] != Null) x->c[right]->p = y; 31 x->p = y->p; 32 if (y->p != Null) { 33 if (y->p->c[0] == y) { 34 y->p->c[0] = x; 35 } else { 36 y->p->c[1] = x; 37 } 38 } 39 x->c[right] = y; 40 y->p = x; 41 if (y == Root) Root = x; 42 up(y); 43 } 44 45 void splay(Node *x, Node *f) { 46 while (x->p != f) { 47 if (x->p->p == f) { 48 if (x->p->c[0] == x) { 49 rotate(x, 1); 50 } else { 51 rotate(x, 0); 52 } 53 } else { 54 Node *y = x->p, *z = y->p; 55 if (z->c[0] == y) { 56 if (y->c[0] == x) { 57 rotate(y, 1); 58 rotate(x, 1); 59 } else { 60 rotate(x, 0); 61 rotate(x, 1); 62 } 63 } else { 64 if (y->c[0] == x) { 65 rotate(x, 1); 66 rotate(x, 0); 67 } else { 68 rotate(y, 0); 69 rotate(x, 0); 70 } 71 } 72 } 73 } 74 up(x); 75 } 76 77 Node *getPos(int pos) { 78 // cout << pos << "??" << endl; 79 Node *p = Root; 80 pos++; 81 // cout << p->cnt << ' ' << p->data << ' ' << pos << endl; 82 // cout << p->c[0]->cnt << ' ' << p->c[0]->data << ' ' << pos << endl; 83 while (true) { 84 int cnt = p->c[0]->cnt; 85 // cout << cnt << ' ' << pos << endl; 86 if (pos == cnt + 1) { 87 break; 88 } else if (pos <= cnt) { 89 p = p->c[0]; 90 } else { 91 pos -= cnt + 1; 92 p = p->c[1]; 93 } 94 } 95 return p; 96 } 97 98 void inTra(Node *x) { 99 if (x == Null) return ; 100 inTra(x->c[0]); 101 cout << x->data << ' '; 102 inTra(x->c[1]); 103 } 104 105 void insPos(int elem, int val, int pos) { 106 // cout << "here " << pos << endl; 107 // inTra(Root); 108 Node *pl = getPos(pos), *pr = getPos(pos + 1); 109 // cout << pl->data << "= =" << pr->data << " ~~ " << pl->cnt << "!!" << pr->cnt << endl; 110 Node *tmp = new Node(elem, val, 1); 111 splay(pl, Null); 112 splay(pr, pl); 113 pr->c[0] = tmp; 114 tmp->p = pr; 115 tmp->c[0] = tmp->c[1] = Null; 116 splay(tmp, Null); 117 } 118 119 void init() { 120 Null = new Node(); 121 Head = Root = new Node(inf, 0, 2); 122 Tail = new Node(inf, 0, 1); 123 Root->c[1] = Tail; 124 Root->c[0] = Root->p = Null; 125 Tail->p = Root; 126 Tail->c[0] = Tail->c[1] = Null; 127 } 128 129 int getMax(int pos) { 130 Node *pl = getPos(0), *pr = getPos(pos + 1); 131 // cout << pl->data << "= =" << pr->data << endl; 132 splay(pl, Null); 133 splay(pr, pl); 134 // inTra(Root); 135 // cout << "tra~~" << endl; 136 pr = pr->c[0]; 137 if (pr == Head || pr == Tail) return 0; 138 return pr->max; 139 } 140 141 int main() { 142 // freopen("in", "r", stdin); 143 int n, T, x; 144 scanf("%d", &T); 145 for (int cas = 1; cas <= T; cas++) { 146 init(); 147 scanf("%d", &n); 148 printf("Case #%d:\n", cas); 149 int LIS = 0; 150 for (int i = 1; i <= n; i++) { 151 scanf("%d", &x); 152 int tmp = getMax(x); 153 // cout << "tmp " << tmp << endl; 154 LIS = max(LIS, tmp + 1); 155 printf("%d\n", LIS); 156 // cout << "can not insert?" << endl; 157 insPos(i, tmp + 1, x); 158 // cout << "no!!" << endl; 159 // inTra(Root); 160 // puts(""); 161 } 162 puts(""); 163 } 164 return 0; 165 }
线段树的之后补上。
UPD:
解释一下我的线段树法的操作。首先,我把插入的位置倒序插入线段树中,从而得到每个数最终的位置。然后再正序模拟插入过程,更新LIS的值。
线段树版本:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 6 using namespace std; 7 8 #define lson l, m, rt << 1 9 #define rson m + 1, r, rt << 1 | 1 10 11 const int N = 111111; 12 int mx[N << 2], cnt[N << 2]; 13 14 void up1(int rt) { 15 cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1]; 16 } 17 18 void build1(int l, int r, int rt) { 19 if (l == r) { 20 cnt[rt] = 1; 21 return ; 22 } 23 int m = l + r >> 1; 24 build1(lson); 25 build1(rson); 26 up1(rt); 27 } 28 29 int ins1(int x, int l, int r, int rt) { 30 if (l == r) { 31 cnt[rt] = 0; 32 return l; 33 } 34 int m = l + r >> 1, ret; 35 if (cnt[rt << 1] >= x) { 36 ret = ins1(x, lson); 37 } else { 38 ret = ins1(x - cnt[rt << 1], rson); 39 } 40 up1(rt); 41 return ret; 42 } 43 44 int rec[N], id[N]; 45 46 void PRE(int n) { 47 for (int i = 0; i < n; i++) scanf("%d", &rec[i]); 48 build1(0, n - 1, 1); 49 for (int i = n - 1; i >= 0; i--) id[i] = ins1(rec[i] + 1, 0, n - 1, 1); 50 // for (int i = 0; i < n; i++) cout << i << " : " << id[i] << ' ' << rec[i] << endl; 51 } 52 53 void up2(int rt) { 54 mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); 55 } 56 57 void build2(int l, int r, int rt) { 58 cnt[rt] = mx[rt] = 0; 59 if (l == r) return ; 60 int m = l + r >> 1; 61 build2(lson); 62 build2(rson); 63 } 64 65 void ins2(int x, int val, int l, int r, int rt) { 66 if (l == r) { 67 mx[rt] = val; 68 return ; 69 } 70 int m = l + r >> 1; 71 if (x <= m) ins2(x, val, lson); 72 else ins2(x, val, rson); 73 up2(rt); 74 } 75 76 int query2(int L, int R, int l, int r, int rt) { 77 if (L <= l && r <= R) { 78 return mx[rt]; 79 } 80 int m = l + r >> 1, ret = 0; 81 if (L <= m) ret = max(ret, query2(L, R, lson)); 82 if (m < R) ret = max(ret, query2(L, R, rson)); 83 return ret; 84 } 85 86 void work(int n) { 87 int tmp, curMax = 0; 88 build2(0, n - 1, 1); 89 for (int i = 0; i < n; i++) { 90 tmp = query2(0, id[i], 0, n - 1, 1); 91 curMax = max(curMax, tmp + 1); 92 printf("%d\n", curMax); 93 ins2(id[i], tmp + 1, 0, n - 1, 1); 94 } 95 } 96 97 int main() { 98 // freopen("in", "r", stdin); 99 int T, n; 100 scanf("%d", &T); 101 for (int i = 1; i <= T; i++) { 102 scanf("%d", &n); 103 printf("Case #%d:\n", i); 104 PRE(n); 105 work(n); 106 puts(""); 107 } 108 return 0; 109 }
——written by Lyon