题目链接
经典三维偏序,求这样的一个最长上升子序列:,,,其中,id这个很容易被忽略掉。
然后我们可以直接用外层cdq套内层cdq的方式去解决这个问题了。
第一维的x直接用sort排序,这里就不管了,接下去,第二维的y呢,我们用外层cdq去解决,因为要求一个上升子序列,所以可以先对左区间处理完,然后将左区间的贡献先给右区间,然后再处理右区间内的左区间,然后逐步这样往下即可。
关于输出答案,也就是要输出字典序最小的最长上升子序列,我们可以先得到每个点的当前值可以是由前面的哪个id转移过来的,然后这里可以用一个vector维护一下,然后推一个spfa求出每个点的下一个最长子序列上的点的最小字典序可以是哪个。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 5e4 + 7;
struct node
{
int x, y, id; int op;
node(int a=0, int b=0, int c=0):x(a), y(b), id(c) {}
friend bool operator < (node e1, node e2) { return e1.x == e2.x ? (e1.y == e2.y ? e1.id < e2.id : e1.y < e2.y) : e1.x > e2.x; }
} t[maxN], cop[maxN], b[maxN];
inline bool cmp_y(node e1, node e2) { return e1.y == e2.y ? e1.id < e2.id : e1.y < e2.y; }
int N, ans[maxN];
vector<int> las[maxN];
void CDQ_In(int l, int r)
{
if(l == r) return;
int mid = HalF;
CDQ_In(l, mid); CDQ_In(mid + 1, r);
int ql = l, qr = mid + 1, pos = l, cnt = 0; vector<int> cid;
while(ql <= mid || qr <= r)
{
if(qr > r || (ql <= mid && b[ql].id <= b[qr].id))
{
if(!b[ql].op)
{
if(cnt < ans[b[ql].id])
{
cid.clear();
cnt = ans[b[ql].id];
cid.push_back(b[ql].id);
}
else if(cnt == ans[b[ql].id])
{
cid.push_back(b[ql].id);
}
}
cop[pos ++] = b[ql ++];
}
else
{
if(b[qr].op)
{
if(ans[b[qr].id] < cnt + 1)
{
las[b[qr].id].clear();
ans[b[qr].id] = cnt + 1;
int len = (int)cid.size();
for(int i=0; i<len; i++) las[b[qr].id].push_back(cid[i]);
}
else if(cnt && ans[b[qr].id] == cnt + 1)
{
int len = (int)cid.size();
for(int i=0; i<len; i++) las[b[qr].id].push_back(cid[i]);
}
}
cop[pos ++] = b[qr ++];
}
}
for(int i=l; i<=r; i++) b[i] = cop[i];
}
void cdq(int l, int r)
{
if(l == r) return;
int mid = HalF;
sort(t + l, t + r + 1);
cdq(l, mid);
sort(t + l, t + mid + 1, cmp_y);
sort(t + mid + 1, t + r + 1, cmp_y);
int ql = l, qr = mid + 1, pos = l;
while(ql <= mid || qr <= r)
{
if(qr > r || (ql <= mid && t[ql].y <= t[qr].y))
{
t[ql].op = 0;
cop[pos ++] = t[ql ++];
}
else
{
t[qr].op = 1;
cop[pos ++] = t[qr ++];
}
}
for(int i=l; i<=r; i++) b[i] = cop[i];
CDQ_In(l, r);
cdq(mid + 1, r);
}
int dp[maxN];
queue<int> Q;
bool inque[maxN];
void Out_put(int _UP)
{
while(!Q.empty()) Q.pop();
for(int i=0; i<=N; i++)
{
if(ans[i] == _UP)
{
inque[i] = true;
Q.push(i);
dp[i] = 0;
}
else
{
inque[i] = false;
dp[i] = INF;
}
}
while(!Q.empty())
{
int u = Q.front(); Q.pop(); inque[u] = false;
int len = (int)las[u].size();
for(int i=0, v; i<len; i++)
{
v = las[u][i];
if(ans[v] == ans[u] - 1)
{
if(dp[v] > u)
{
dp[v] = u;
if(!inque[v])
{
inque[v] = true;
Q.push(v);
}
}
}
}
}
int u = dp[0];
bool fir = true;
while(u)
{
if(!fir) printf(" ");
printf("%d", u);
fir = false;
u = dp[u];
}
printf("\n");
}
void init()
{
for(int i=1; i<=N; i++)
{
ans[i] = 1;
las[i].clear();
las[i].push_back(0);
}
}
signed main()
{
while(scanf("%d", &N) != EOF)
{
init();
for(int i=1; i<=N; i++) scanf("%d", &t[i].x);
for(int i=1; i<=N; i++) scanf("%d", &t[i].y);
for(int i=1; i<=N; i++) t[i].id = i;
sort(t + 1, t + N + 1);
cdq(1, N);
int ans_maxx = 0;
for(int i=1; i<=N; i++) ans_maxx = max(ans_maxx, ans[i]);
printf("%d\n", ans_maxx);
Out_put(ans_maxx);
}
return 0;
}