看到这个问题,我们先分析下什么时候不可行。

为了方便我们称的区间为区间,称的区间为区间

经过漫长的讨论,我们发现只有当一个区间是一个区间的子区间时答案是不存在,其他情况都可以通过构造得到。

那么问题就转化为判断每一个区间是否是某个区间的子区间。

不难想到把区间要求离线下来,同时对于每个点用并查集维护它所在区间的左端点和右端点(即把连续的区间拼接起来)。只要一个区间里的每一个点都满足它所在的区间的左端点不大于区间的左端点它所在的区间的右端点不小于区间的右端点,那么这个区间就是区间的子区间。

构造的话我们只要搞一个差分数组就行了。

#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;
}