Boring Class HDU - 5324 (CDQ分治)

Mr. Zstu and Mr. Hdu are taking a boring class , Mr. Zstu comes up with a problem to kill time, Mr. Hdu thinks it’s too easy, he solved it very quickly, what about you guys? 
Here is the problem: 
Give you two sequences L1,L2,...,Ln and R1,R2,...,Rn
Your task is to find a longest subsequence v1,v2,...vm satisfies 
v11,vmn,vi<vi+1 .(for i from 1 to m - 1) 
LviLvi+1,RviRvi+1(for i from 1 to m - 1) 
If there are many longest subsequence satisfy the condition, output the sequence which has the smallest lexicographic order. 


InputThere are several test cases, each test case begins with an integer n. 
1n50000 
Both of the following two lines contain n integers describe the two sequences. 
1Li,Ri109 
OutputFor each test case ,output the an integer m indicates the length of the longest subsequence as described. 
Output m integers in the next line. 
Sample Input

5
5 4 3 2 1
6 7 8 9 10
2
1 2
3 4

Sample Output

5
1 2 3 4 5
1
1

题意
给你两个序列Li,Ri,求构造一个最长的子序列,使得L递减, R递增。在保证最长的前提下要求字典序最小。(vj)
思路:
很明显的可以看出是三维偏序问题。
但是这题要求的是最长的序列,而不是对于每一个元素求解,所以需要要对CDQ分治的部分做相应的更改。
我们设对每一个元素,求以它未开始的符合题意的序列长度最长是多长。只有这样,才能顺利求出字典序最小。
那么对于每一个元素,在处理其答案时,其右侧的元素答案都应该已知了。
传统分治的做法显然不能满足这个要求,因为在如果先治左边,那么右边未知,便无法知道答案。
于是我们想到先分治右侧,再分治左侧。
但是这还不够,在对左侧求解过程中,当前右侧的答案可能并非是全局的答案,这一点的原因我不知道该如何描述,但是在3层CDQ里面就已经很明显了。
所以我们先分治右边,在处理当前层,再分治左边。
由于分治顺序的特殊性,归并排序已经不适用了,所以只能使用快排。
注意在处理左侧之前,要回复左侧原来的顺序。
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>

#define fuck(x) clog<<#x<<" = "<<x<<endl;
#define debug(a, x) clog<<#a<<"["<<x<<"] = "<<a[x]<<endl;
#define lson l,mid,ls
#define rson mid+1,r,rs
#define ls (rt<<1)
#define rs ((rt<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int loveisblue = 486;
const int maxn = 100086;
const int maxm = 100086;
const int inf = 0x3f3f3f3f;
const ll Inf = 999999999999999999;
const int mod = 1000000007;
const double eps = 1e-6;
const double pi = acos(-1);

int n;
struct node{
    int a,b,c,ans;
}cdq[maxn];
int mx[maxn<<2];
void update(int l,int r,int rt,int pos,int val){
    if(l==r){
        mx[rt]=val;
        return;
    }
    int mid = (l+r)>>1;
    if(pos<=mid){
        update(lson,pos,val);
    }else{
        update(rson,pos,val);
    }
    mx[rt]=max(mx[ls],mx[rs]);
}

int query(int l,int r,int rt,int L,int R){
    if(L<=l&&R>=r){
        return mx[rt];
    }
    int ans = 0;
    int mid = (l+r)>>1;
    if(L<=mid){
        ans=  max(ans,query(lson,L,R));
    }if(R>mid){
        ans = max(ans,query(rson,L,R));
    }
    return ans;
}
int num[maxn];
int rem[maxn],tot;
int get_id(int x){
    return lower_bound(rem+1,rem+1+tot,x)-rem;
}

bool cmp1(node a,node b){
    if(a.b!=b.b)return a.b>b.b;
    return a.c<b.c;
}
bool cmp(node a,node b){
    return a.a<b.a;
}

void solve(int l,int r){
    if(l==r){ return;}
    int mid = (l+r)>>1;
    solve(mid+1,r);
    int t1 = mid,t2 = r;
    int cur = r+1;
    sort(cdq+l,cdq+mid+1,cmp1);
    sort(cdq+mid+1,cdq+r+1,cmp1);
    while (t1>=l||t2>mid) {
        if (t1 < l || (t2 > mid && cdq[t1].b >= cdq[t2].b)) {
            update(1, tot, 1, get_id(cdq[t2].c), cdq[t2].ans);
            t2--;
        } else {
            cdq[t1].ans = max(cdq[t1].ans, query(1, tot, 1,  get_id(cdq[t1].c) ,tot)+1);
            t1--;
        }
    }
    for(int i=mid+1;i<=r;i++){
        update(1,tot,1,get_id(cdq[i].c),0);
    }
    sort(cdq+l,cdq+mid+1,cmp);
    solve(l,mid);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    while (scanf("%d",&n)!=EOF) {
        tot = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &num[i]);
        }
        for (int i = 1; i <= n; i++) {
            int x;
            scanf("%d", &x);
            rem[++tot] = x;
            cdq[i] = node{i, num[i], x, 1};
        }
        sort(rem+1,rem+1+tot);
        tot = unique(rem+1,rem+1+tot)-rem-1;
        solve(1,n);
        sort(cdq+1,cdq+1+n,cmp);
        int ans = 0;
        for(int i=1;i<=n;i++){
            ans = max(cdq[i].ans,ans);
        }
        printf("%d\n",ans);
        int last = 0;
        cdq[0].b = inf;
        cdq[0].c = -1;
        for(int i=1;i<=n;i++){
            if(cdq[i].ans==ans&&cdq[i].b<=cdq[last].b&&cdq[i].c>=cdq[last].c){
                ans--;
                last=i;
                if(ans==0){printf("%d\n",i);}
                else printf("%d ",i);
            }
        }
    }
    return 0;
}
View Code



posted @ 2019-08-13 22:06  断腿三郎  阅读(209)  评论(0编辑  收藏  举报