看到这个问题,我们先分析下什么时候不可行。
为了方便我们称的区间为
区间,称
的区间为
区间
经过漫长的讨论,我们发现只有当一个区间是一个
区间的子区间时答案是不存在,其他情况都可以通过构造得到。
那么问题就转化为判断每一个区间是否是某个
区间的子区间。
不难想到把区间要求离线下来,同时对于每个点用并查集维护它所在
区间的左端点和右端点(即把连续的
区间拼接起来)。只要一个
区间里的每一个点都满足它所在的
区间的左端点不大于
区间的左端点且它所在的
区间的右端点不小于
区间的右端点,那么这个
区间就是
区间的子区间。
构造的话我们只要搞一个差分数组就行了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=500010;
const ll INF=2147483647;
struct node
{
ll x,y;
};
node f[maxn],c[maxn];
ll n,m,t,l,r,a[maxn],s[maxn],sum,cur,pd,cnt,fal[maxn],far[maxn];
vector<ll>e;
bool vis[maxn];
ll findl(ll x)
{
if(fal[x]==x)return x;
return fal[x]=findl(fal[x]);
}
ll findr(ll x)
{
if(far[x]==x)return x;
return far[x]=findr(far[x]);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
fal[i]=i;
far[i]=i;
}
while(m--)
{
cin>>t>>l>>r;
if(t==1)//对于1区间我们更新信息
{
for(int i=l;i<=r;i++)
{
if(i!=r)a[i]+=1000;//差分
vis[i]=1;
if(findl(i)>l)fal[findl(i)]=l;
if(findr(i)<r)far[findr(i)]=r;
}
}
else//0区间就离线下来
{
c[++cnt].x=l;
c[cnt].y=r;
}
}
for(int i=1;i<=n;i++)//f数组是该点最终所处1区间的左右端点
{
f[i].x=(vis[i] ? findl(i) : INF);
f[i].y=(vis[i] ? findr(i) : -1);
}
for(int i=1;i<=cnt;i++)
{
pd=0;
for(int j=c[i].x;j<=c[i].y;j++)
{
if(f[j].x!=INF&&f[j].y!=-1)
{
if(c[i].y<=f[j].y&&c[i].x>=f[j].x)pd=1;
}
if(j!=c[i].y)a[j]--;//差分
}
if(pd)//是子区间
{
cout<<"NO";
return 0;
}
}
s[1]=1;
sum=1;
for(int i=2;i<=n;i++)
{
sum+=a[i-1];
s[i]=sum;
cur=max(1-s[i],cur);//这里防止出现小于1的数
}
cout<<"YES"<<"\n";
for(int i=1;i<=n;i++)cout<<s[i]+cur<<" ";
return 0;
} 


京公网安备 11010502036488号