做法一:树状数组套笛卡尔树。
保证字典序最小,从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;
}