看到这个问题,我们先分析下什么时候不可行。
为了方便我们称的区间为
区间,称
的区间为
区间
经过漫长的讨论,我们发现只有当一个区间是一个
区间的子区间时答案是不存在,其他情况都可以通过构造得到。
那么问题就转化为判断每一个区间是否是某个
区间的子区间。
不难想到把区间要求离线下来,同时对于每个点用并查集维护它所在
区间的左端点和右端点(即把连续的
区间拼接起来)。只要一个
区间里的每一个点都满足它所在的
区间的左端点不大于
区间的左端点且它所在的
区间的右端点不小于
区间的右端点,那么这个
区间就是
区间的子区间。
构造的话我们只要搞一个差分数组就行了。
#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; }