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. 

Boring Class HDU - 5324 (CDQ分治)

InputThere are several test cases, each test case begins with an integer n. 
 
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

相关文章: