传送门
解析:
按照第一位 a a a排序从大到小,求 b b b的最少的下降序列的划分数。
转换一下,求 b b b的最少下降序列个数。
根据 D i l w o r t h Dilworth Dilworth定理,由于没有相等,我们要求的就是 b b b的最长上升子序列的长度。
对于输出方案,我们在每个上升序列的位置维护一个 h e a d head head,能够补到这个位置的数就能够在最后的下降序列中出现在以 h e a d head head开头的序列中。并查集维护一下就好了。
其实排序还有一种骚操作(zxyoi瞎yy出来的),由于 a , b a,b a,b都是一个 1 − n 1-n 1−n的全排列,所以我们直接用 a a a来存 b b b,同时记录一下这是输入的第几个数。
那么序自然就被排好了。。。
但是后面的复杂度仍然是 O ( n l o g n ) O(nlogn) O(nlogn)因为二分嘛。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline void outint(int a){
static char ch[13];
if(a==0)return (void)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=1000006;
int fa[N];
inline int getfa(int x){
while(x^fa[x])x=fa[x]=fa[fa[x]];
return x;
}
inline void merge(int u,int v){
u=getfa(u);
v=getfa(v);
fa[max(u,v)]=min(u,v);
}
int pos[N],tot;
int len;
int a[N],head[N];
int b[N];
int id[N];
int n;
signed main(){
n=getint();
for(int re i=1;i<=n;++i){
int x=getint(),
y=getint();
b[x]=y;
id[x]=i;
fa[i]=i;
}
for(int re i=n;i;--i){
int c=b[i];
if(len==0||c>a[len]){
a[++len]=c;
head[len]=id[i];
}
else{
int k=lower_bound(a+1,a+len+1,c)-a;
merge(head[k],id[i]);
a[k]=c;
}
}
cout<<len<<"\n";
for(int re i=1;i<=n;++i)if(fa[i]==i)pos[i]=++tot;
for(int re i=1;i<=n;++i)outint(pos[getfa(i)]),pc(' ');
return 0;
}