题目链接:hdu 5324 Boring Class
做法一:树状数组套笛卡尔树。
保证字典序最小,从N->1方向遍历。树状数组维护第二维,每个节点对应一棵笛卡尔树,笛卡尔树的key值对应第三维,val值为随机值,控制树高。然后笛卡尔树的每个节点维护len,idx,mlen,midx将每次查询复杂度控制在log(n) * log(n)
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int maxn = 50010; #define lowbit(x) ((x)&(-x)) struct Node { Node* ch[2]; int key, len, idx, val; int mlen, midx; Node () {} Node (int key, int len, int idx):key(key), len(len), idx(idx), mlen(len), midx(idx) { val = rand(); ch[0] = ch[1] = NULL; } void maintain() { mlen = len; midx = idx; for (int i = 0; i < 2; i++) { if (ch[i] != NULL && (ch[i]->mlen > mlen || (ch[i]->mlen == mlen && ch[i]->midx < midx))) { mlen = ch[i]->mlen; midx = ch[i]->midx; } } } int cmp (int v) { if (v == key) return -1; return v < key ? 0 : 1; } }; void findMax(Node* a, Node* b) { if (a->mlen < b->mlen || (a->mlen == b->mlen && a->midx > b->midx)) *a = *b; } namespace Treap { int cntNode; Node nd[maxn * 10]; void init () { cntNode = 0; } Node* newNode (int key, int len, int idx) { nd[++cntNode] = Node(key, len, idx); return &nd[cntNode]; } void rotate(Node* &o, int d) { Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o; o->maintain(); k->maintain(); o = k; } void insert(Node* &o, int key, int len, int idx) { if (o == NULL) o = newNode(key, len, idx); else { int d = o->cmp(key); if (d != -1) { insert(o->ch[d], key, len, idx); if (o->val < o->ch[d]->val) rotate(o, d^1); } else if (len >= o->len) { o->len = len; o->idx = idx; } } o->maintain(); } Node query(Node* o, int key) { if (o == NULL) return Node(-1, 0, -1); else { Node ret, tmp; if (o->key == key) { ret = Node(o->key, o->len, o->idx); if (o->ch[1]) findMax(&ret, o->ch[1]); } else if (o->key > key) { ret = Node(o->key, o->len, o->idx); if (o->ch[1]) findMax(&ret, o->ch[1]); tmp = query(o->ch[0], key); findMax(&ret, &tmp); } else { ret = query(o->ch[1], key); } return ret; } } } namespace Bit { int n; Node* fenw[maxn]; void init (int k) { n = k; memset(fenw, 0, sizeof(fenw)); } void add (int x, int key, int len, int idx) { while (x < n) { Treap::insert(fenw[x], key, len, idx); x += lowbit(x); } } Node search(int x, int level) { Node ret, tmp; ret = Node(-1, 0, -1); while (x > 0) { tmp = Treap::query(fenw[x], level); findMax(&ret, &tmp); x -= lowbit(x); } return ret; } } struct Pi { int L, R, id; bool operator < (const Pi& u) const { return L < u.L; } }P[maxn]; bool cmp(const Pi& a, const Pi& b) { return a.id < b.id; } int N, M, Idx[maxn], Pre[maxn]; void print (Node& ans) { int mv = ans.midx; printf("%d\n", ans.mlen); while (true) { printf("%d", mv); if (Pre[mv] == -1) break; printf(" "); mv = Pre[mv]; } printf("\n"); } int main () { while (scanf("%d", &N) == 1) { for (int i = 1; i <= N; i++) { scanf("%d", &P[i].L); P[i].id = i; } for (int i = 1; i <= N; i++) scanf("%d", &P[i].R); sort(P + 1, P + N + 1); M = 0; Idx[1] = ++M; for (int i = 2; i <= N; i++) { if (P[i].L != P[i-1].L) Idx[i] = ++M; else Idx[i] = Idx[i-1]; } for (int i = 1; i <= N; i++) P[i].L = Idx[i]; sort(P + 1, P + N + 1, cmp); Bit::init(M + 1); Treap::init(); Node ans = Node(-1, 0, -1), tmp; for (int i = N; i > 0; i--) { tmp = Bit::search(P[i].L, P[i].R); Pre[i] = tmp.midx; tmp.mlen = tmp.mlen + 1; tmp.midx = i; Bit::add(P[i].L, P[i].R, tmp.mlen, tmp.midx); findMax(&ans, &tmp); } print(ans); } return 0; }
同样,保证字典序最小,从右向左遍历,即下标为第一维。接着按照L值排序id,每次二分,优先处理后半段,在由后半段更新前半段。树状数组离散R维。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 50005; const int inf = 0x3f3f3f3f; #define lowbit(x) ((-x)&(x)) struct Pi { int idx, L, R; }P[maxn]; int N, ans, rans, dp[maxn], pre[maxn]; int bw, sy[maxn], ty[maxn << 1], sz[maxn], tz[maxn]; bool cmp (const int& a, const int& b) { return P[a].L > P[b].L; } namespace Bit { int n, fenw[maxn], rec[maxn]; void init (int k) { n = k; memset(fenw, 0, (n + 1) * sizeof(int)); } void add (int x, int k, int id) { while (x <= n) { if (fenw[x] == k) rec[x] = min(rec[x], id); else if (fenw[x] < k) fenw[x] = k, rec[x] = id; x += lowbit(x); } } int search (int x, int& id) { int ret = id = 0; while (x) { if (fenw[x] > ret) ret = fenw[x], id = rec[x]; else if (fenw[x] == ret) id = min(id, rec[x]); x -= lowbit(x); } return ret; } }; void init () { bw = ans = rans = 0; for (int i = 1; i <= N; i++) scanf("%d", &P[i].L); for (int i = 1; i <= N; i++) { scanf("%d", &P[i].R); sy[i] = i, dp[i] = 1; } sort(sy + 1, sy + N + 1, cmp); } void solve (int l, int r) { if (l == r) { if (dp[l] > ans) ans = dp[l], rans = l; else if (dp[l] == ans) rans = min(rans, l); sz[l] = P[l].R; return; } int mid = (l + r) >> 1, len = r - l + 1; int ml = l, mr = mid + 1; memcpy(ty + bw, sy + l, len * sizeof(int)); for (int i = 0; i < len; i++) { if (ty[bw+i] <= mid) sy[ml++] = ty[bw+i]; else sy[mr++] = ty[bw+i]; } bw += len; solve(mid + 1, r); int n = r - mid, limt = bw, pos, ri = mid + 1; bw -= len; Bit::init(n); //printf("%d %d %d:\n", l, r, len); for (int i = limt - 1; i >= bw; i--) { if (ty[i] > mid) { pos = lower_bound(sz + ri, sz + ri + n, P[ty[i]].R) - (sz + ri); Bit::add(n - pos, dp[ty[i]], ty[i]); //printf("add: %d %d %d\n", n - pos, dp[i], i); continue; } pos = lower_bound(sz + ri, sz + ri + n, P[ty[i]].R) - (sz + ri); //printf("check:%d\n", pos); if (pos >= 0) { int tmp; int ret = Bit::search(n - pos, tmp) + 1; //printf("search:%d %d %d\n", n - pos, ret, tmp); if (dp[ty[i]] < ret) dp[ty[i]] = ret, pre[ty[i]] = tmp; else if (dp[ty[i]] == ret) pre[ty[i]] = min(pre[ty[i]], tmp); } } solve(l, mid); merge(sz + l, sz + ri, sz + ri, sz + l + len, tz); memcpy(sz + l, tz, len * sizeof(int)); } int main () { while (scanf("%d", &N) == 1) { init(); solve(1, N); printf("%d\n", ans); for (int i = 1; i <= ans; i++) { printf("%d%c", rans, i == ans ? '\n' : ' '); rans = pre[rans]; } } return 0; }