题意:
给你两个序列,两个序列都有n个数。然后让你找到一个位置序列,对应到两个序列上,使得新的L序列非递增,R序列非递减。
问你最长的长度是多少,并输出字典序最小的方案。
思路:
人生的第一道cdq分治,一直觉得这些类型学会了放在比赛也做不出来就没去学了。。。但看到辣么多人会做。。。赶紧搞起。
思路、代码盗自别人blog:http://blog.youkuaiyun.com/u013007900/article/details/47111319
由于值太大,先把L、R序列的值都离散化。
首先定义dp[i]:以第i个数为开头的最长长度是多少。(已经定义出dp状态,如果n^2能过,直接dp就可搞了hhh。)
由于要求字典序最小,因此要从后面搞起。如果从前面搞起,dp[i]状态就应该定义为 以第i个数结尾的最长长度,就算让你找到最长长度,但很难得知字典序最小的那个。
大概过程:
先把序列一分为二,既然是从后面搞起,则先把右区间递归搞掉,搞完右区间,然后利用树状数组更新对左区间的影响,清空树状数组后再递归搞左区间。(由于L序列要求非递增,则利用树状数组来保存比当前Li小的Lj的dp最大值。)
最后,我相信不会cdq的还是不知道怎么写,去看代码吧,少年。
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4+5;
typedef long long LL;
struct PP {
int l, r;
int id;
bool operator < (const PP &cmp) const {
if(r != cmp.r) return r < cmp.r;
if(l != cmp.l) return l > cmp.l; //nothing
return id < cmp.id;
}
}a[N];
PP p1[N], p2[N];
int n, tn;
int bit[N<<1];
int ls[N<<1];
int dp[N];
void update(int x, int val) {
while(x <= tn) {
bit[x] = max(bit[x], val);
x += x&(-x);
}
}
int query(int x) {
int ret = 0;
while(x > 0) {
ret = max(ret, bit[x]);
x -= x&(-x);
}
return ret;
}
void clear(int x) {
while(x <= tn) {
bit[x] = 0;
x += x&(-x);
}
}
void cdq(int l, int r) {
if(l == r) {
int &d = dp[a[l].id];
d = max(d, 1);
return ;
}
int mid = (l+r)>>1;
cdq(mid+1, r);
for(int i = mid+1;i <= r; i++) p2[i] = a[i];
for(int i = l; i <= mid; i++) p1[i] = a[i];
sort(p1+l, p1+mid+1);
sort(p2+mid+1, p2+r+1);
for(int i = mid, j = r;i >= l; i--) {
while(j > mid && p2[j].r >= p1[i].r) {
update(p2[j].l, dp[p2[j].id]);
j--;
}
int &e = p1[i].id;
dp[e] = max(dp[e], query(p1[i].l)+1);
}
for(int i = mid+1;i <= r; i++) clear(p2[i].l);
cdq(l, mid);
}
void solve() {
memset(dp, 0, sizeof(dp));
memset(bit, 0, sizeof(bit));
cdq(1, n);
int maxv = -1;
for(int i = 1;i <= n; i++) maxv = max(maxv, dp[i]);
printf("%d\n", maxv);
bool flag = false;
int pre = 0;
for(int i = 1;i <= n; i++) {
if(dp[i] == maxv && (pre == 0||(a[pre].l>=a[i].l&&a[pre].r<=a[i].r))) {
if(!flag) {
flag = true;
printf("%d", i);
}
else printf(" %d", i);
maxv--;
pre = i;
}
}
puts("");
}
int main() {
while(scanf("%d", &n) != EOF) {
for(int i = 1;i <= n; i++) scanf("%d", &a[i].l);
for(int i = 1;i <= n; i++) scanf("%d", &a[i].r);
for(int i = 1;i <= n; i++) a[i].id = i;
int cnt = 0;
for(int i = 1;i <= n; i++) {
ls[cnt++] = a[i].l;
ls[cnt++] = a[i].r;
}
sort(ls, ls+cnt);
cnt = unique(ls, ls+cnt)-ls;
tn = cnt;
for(int i = 1;i <= n; i++) {
a[i].l = lower_bound(ls, ls+cnt, a[i].l)-ls+1;
a[i].r = lower_bound(ls, ls+cnt, a[i].r)-ls+1;
}
solve();
}
return 0;
}