前言
富榄好强啊 !
题目大意
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':' ');
}