题意:
现在有n个人,他们可行的取值范围是li~ri。让你构造一个排序使得它符合每个人的范围,问你这个排序是否是独一无二的。
题解:
首先找一个排序的话,只需要从小到大枚举值,然后查看当前有哪些人包含这个值,将右端点最小的那个人赋予这个值即可。因为这必然是最优的,取右端点最小的话,剩下的人的选择机会更多。
对于是否独一无二的问题,我们只需要选择两个人,使得max(lef[i],lef[j])<=v[i],v[j]<=min(rig[i],rig[j]),就像下面这个样子:
这样的话,他们的值可以互换。
那么我们从小枚举值,并且将包含这个值的人的值加入权值线段树(有点绕)
设val[i]表示第i个人的值是val[i]
p[i]表示值是i的人的序号为p[i]
那么上面的这个意思就是枚举的值是1~n,然后当前的人的序号是p[i],对于lef[x]<=i<=rig[x]的人的val[x]加入到权值线段树中的第val[x]位置。
接下来我们查询lef[i]~rig[i]中是否有人即可。
注意要将自己删掉。
#include<bits/stdc++.h>
using namespace std;
#define pa pair<int,int>
const int N=2e5+5;
int lef[N],rig[N];
struct edge{
int l,r,id;
bool operator< (const edge& a)const {
return l<a.l;
}
}e[N],tmp[N];
bool cmp(edge x,edge y){return x.r<y.r;}
int p[N],val[N];
set<pa>s;
int num[N*4];
void update(int l,int r,int root,int p,int v){
if(l==r){
num[root]+=v;
return ;
}
int mid=l+r>>1;
if(mid>=p)
update(l,mid,root<<1,p,v);
else
update(mid+1,r,root<<1|1,p,v);
num[root]=num[root<<1]+num[root<<1|1];
}
int query(int l,int r,int root,int ql,int qr){
if(!num[root])return -1;
if(l==r)return l;
int mid=l+r>>1;
if(l>=ql&&r<=qr){
if(num[root<<1])
return query(l,mid,root<<1,ql,qr);
return query(mid+1,r,root<<1|1,ql,qr);
}
int ans=-1;
if(mid>=ql)
ans=query(l,mid,root<<1,ql,qr);
if(mid<qr&&ans==-1)
ans=query(mid+1,r,root<<1|1,ql,qr);
return ans;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&lef[i],&rig[i]);
e[i]=tmp[i]={lef[i],rig[i],i};
}
sort(e+1,e+1+n);
int j=1;
for(int i=1;i<=n;i++){
while(j<=n&&i==e[j].l)s.insert({e[j].r,e[j].id}),j++;
p[i]=(*s.begin()).second;
s.erase(s.begin());
val[p[i]]=i;
}
int f=0;
sort(tmp+1,tmp+1+n,cmp);
int now1=1,now2=1;
for(int i=1;i<=n;i++){
int id=p[i];
while(now1<=n&&e[now1].l==i){
update(1,n,1,val[e[now1].id],1);
now1++;
}
update(1,n,1,val[id],-1);
int ans=query(1,n,1,lef[id],rig[id]);
if(~ans){
printf("NO\n");
for(int i=1;i<=n;i++)
printf("%d%c",val[i]," \n"[i==n]);
swap(val[id],val[p[ans]]);
for(int i=1;i<=n;i++)
printf("%d%c",val[i]," \n"[i==n]);
return 0;
}
}
printf("YES\n");
for(int i=1;i<=n;i++)
printf("%d%c",val[i]," \n"[i==n]);
return 0;
}