Jason跳格子

前言

富榄好强啊 !

题目大意

f[i]=max(f[j]+1)其中j

CDQ分治

明显的,我们可以CDQ分治。
对于solve(l,r),先递归处理solve(l,mid),然后我们用[l,mid]更新[mid+1,r]。我们可以按照a排序来做,b用线段树维护,当然排序有第二关键字那就是编号。
常数有点大,可以加个优化:线段树在查询时一个区间最大值为0直接返回0。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=200000+10;
int a[maxn],b[maxn],f[maxn],tree[maxn*4],q[maxn],p[maxn];
bool bz[maxn*4];
int i,j,k,l,t,n,m,top;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
bool cmp(int x,int y){
    return a[x]<a[y]||a[x]==a[y]&&x<y;
}
void mark(int p){
    bz[p]=1;
    tree[p]=0;
}
void down(int p){
    if (bz[p]){
        mark(p*2);
        mark(p*2+1);
        bz[p]=0;
    }
}
void change(int p,int l,int r,int a,int b){
    if (l==r){
        if (b>tree[p]) tree[p]=b;
        return;
    }
    down(p);
    int mid=(l+r)/2;
    if (a<=mid) change(p*2,l,mid,a,b);else change(p*2+1,mid+1,r,a,b);
    if (tree[p*2]>tree[p*2+1]) tree[p]=tree[p*2];else tree[p]=tree[p*2+1];
}
int query(int p,int l,int r,int a,int b){
    if (l==a&&r==b) return tree[p];
    if (!tree[p]) return 0;
    down(p);
    int mid=(l+r)/2,j,k;
    if (b<=mid) return query(p*2,l,mid,a,b);
    else if (a>mid) return query(p*2+1,mid+1,r,a,b);
    else{
        j=query(p*2,l,mid,a,mid);
        k=query(p*2+1,mid+1,r,mid+1,b);
        if (j>k) return j;else return k;
    }
}
void solve(int l,int r){
    if (l==r){
        if (!f[l]) f[l]=1;
        return;
    }
    int mid=(l+r)/2,i,j;
    solve(l,mid);
    fo(i,l,r) q[i]=i;
    sort(q+l,q+r+1,cmp);
    mark(1);
    fo(i,l,r)
        if (q[i]<=mid) change(1,1,top,b[q[i]],f[q[i]]);
        else{
            j=query(1,1,top,1,b[q[i]])+1;
            if (j>f[q[i]]) f[q[i]]=j;
        }
    solve(mid+1,r);
}
int main(){
    freopen("picks.in","r",stdin);freopen("picks.out","w",stdout);
    n=read();
    fo(i,1,n) a[i]=read(),b[i]=read();
    fo(i,1,n) q[i]=b[i];
    sort(q+1,q+n+1);
    top=unique(q+1,q+n+1)-q-1;
    fo(i,1,n) b[i]=lower_bound(q+1,q+top+1,b[i])-q;
    solve(1,n);
    fo(i,1,n) printf("%d%c",f[i],i==n?'\n':' ');
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值