Hdu 5324 Boring Class (cdq分治)

75 篇文章 0 订阅
21 篇文章 0 订阅

解析:因为是最小字典序,所以从右往左DP。

dp[i] = max(dp[j]+1) i < j,L[i]>=L[j],R[i]<=R[j]

因为这是三维上的问题,自然的就能想到cdq分治了。

在一个区间[l,r]内,先对[mid+1,r]递归,按L[]排序后建立一个对R的线段树,来计算[mid+1,r]的影响,再递归[l,r]。

这里说的比较笼统,不过熟悉cdq分治的同学应该能立马明白我说的什么吧!

[code]:

#include<cstdio>
#include<cstring>
#include<algorithm>

#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn = 1e5+5;

int mc[2*maxn],hah;
int n,L[maxn],R[maxn],dp[maxn],pre[maxn];
int C[8*maxn];
int que[maxn];

void init(){
    hah = 0;
    memset(pre,-1,(n+1)*sizeof(int));
}
void push_up(int rt){
    if(dp[C[rt<<1]] != dp[C[rt<<1|1]]){
        C[rt] = dp[C[rt<<1]]>dp[C[rt<<1|1]]?C[rt<<1]:C[rt<<1|1];
    }else C[rt] = min(C[rt<<1],C[rt<<1|1]);
}

void build(int l,int r,int rt){
    C[rt] = 0;
    if(l == r) return;
    int mid = (l+r)>>1;
    build(lson);build(rson);
}

void update(int k,int x,int l,int r,int rt){
    if(l == r){
        if(dp[x]>dp[C[rt]]) C[rt] = x;
        else if(dp[x]==dp[C[rt]]) C[rt] = min(C[rt],x);
        return;
    }
    int mid = (l+r)>>1;
    if(k <= mid) update(k,x,lson);
    else update(k,x,rson);
    push_up(rt);
}

void debug(int l,int r,int rt){
    if(l ==r){
        printf("%d ",C[rt]);
        return;
    }
    int mid = (l+r)>>1;
    debug(lson);debug(rson);
}

void clr(int k,int l,int r,int rt){
    C[rt] = 0;
    if(l == r) return;
    int mid = (l+r)>>1;
    if(k <= mid) clr(k,lson);
    else clr(k,rson);
}

int query(int a,int b,int l,int r,int rt){
    if(a <= l&&r <= b) return C[rt];
    if(l > b||r < a) return 0;
    int p1,p2,mid = (l+r)>>1;
    p1 = query(a,b,lson);p2 = query(a,b,rson);
    if(dp[p1]!=dp[p2]) return dp[p1]>dp[p2]?p1:p2;
    else return min(p1,p2);
}

bool cmp(const int &i,const int &j){
    return L[i]!=L[j]?L[i]<L[j]:i > j;
}
void cdq(int l,int r){
    if(l>=r) return;
    int u,v,i,j,mid,len;
    mid = (l+r)>>1;
    cdq(mid+1,r);
    len = 0;
    for(i = l;i <= r;i++) que[len++] = i;
    sort(que,que+len,cmp);
    for(i = 0;i < len;i++){
        u = que[i];
        if(u > mid){
            update(R[u],u,1,hah,1);
        }else{
            v = query(R[u],hah,1,hah,1);
            if(!v) continue;
            if(dp[u]<dp[v]+1){
                dp[u] = dp[v]+1;pre[u] = v;
            }else if(dp[u]==dp[v]+1) pre[u] = min(pre[u],v);
        }
    }
    for(i = 0;i < len;i++){
        if(que[i]>mid) clr(R[que[i]],1,hah,1);
    }

    cdq(l,mid);
}

int main(){
    int i,j;
    while(~scanf("%d",&n)){
        init();
        for(i = 1;i <= n;i++) scanf("%d",&L[i]);
        for(i = 1;i <= n;i++) scanf("%d",&R[i]);
        for(i = 1;i <= n;i++){
            mc[hah++] = L[i];mc[hah++] = R[i];
            dp[i] = 1;
        }
        sort(mc,mc+hah);
        hah = unique(mc,mc+hah)-mc;
        for(i = 1;i <= n;i++){
            L[i] = lower_bound(mc,mc+hah,L[i])-mc+1;
            R[i] = lower_bound(mc,mc+hah,R[i])-mc+1;
        }
        build(1,hah,1);
        cdq(1,n);
        int tmp = -1;
        for(i = 1;i <= n;i++){
            tmp = max(tmp,dp[i]);
        }
        for(i = 1;i <= n;i++) if(dp[i]==tmp) break;
        printf("%d\n%d",dp[i],i);
        while(pre[i]!=-1){
            printf(" %d",pre[i]);
            i = pre[i];
        }
        putchar('\n');
    }
    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值