hdu 5324 Boring Class(树状数组+笛卡尔树 | 树状数组+cdq分治)

来源:互联网 发布:java覆盖例子 编辑:程序博客网 时间:2024/05/29 02:22

题目链接: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;elseIdx[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;}


做法二:树状数组+cdq分治。

同样,保证字典序最小,从右向左遍历,即下标为第一维。接着按照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];elsesy[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;}



0 0