题目大意:构造一个长度为的排列,使得满足个约束条件: 区间逆序对个数是奇数或偶数。满足这些约束条
件的区间包含或不相交.
分析:关注其保证区间不相交,即:
所有的区间不相交或包含意味着这些区间可以构成一个树形结构。将区间视为一个点,可发现区间构成了一棵树。不妨建立一个号区间作为根节点,范围至(即包含所有的区间),接下来,为了使代码更为简洁,可以建立个长度为的叶节点,再进行 :
由于小区间的改变更为灵活,我们的换数字可从小区间开始(起始排列为至)
---1.区间长度小于:由于我们建立了个长度为的叶节点,对于这种情况其实本不需操作,但输入中可能存在长度为的区间且逆序数对为奇数,此时无法构造序列,应输出
---2.区间长度大于等于且不为号区间(号区间无需操作): 由于建立了个长度为的叶节点,因此区间长度大于等于的节点必然是父节点(儿子数量大于等于),父节点的逆序数对的数量由儿子决定,经过手动操作发现,
--------------------------若所有子节点的奇偶和等于父节点的奇偶和,则无需操作
--------------------------若所有子节点的奇偶和不等于父节点的奇偶和,可以发现更改第一孩子区间的最大值与第二孩子区间的最小值即可满足题意 -----
: 与 合并,目的逆序数对为奇数个,可交换,使满足题意
参考代码
using namespace std;
const int M=1e3+7;
struct Tree{
int l,r,w;
}t[2*M];
int n,m,flag=0;
int fa[2*M],p[M],pos[M];
vector<int> g[2*M];
bool Cmp(Tree p,Tree q){
if(p.l!=q.l) return p.l<q.l;
return p.r>q.r;
}
void DFS(int u){
int v,sum=0;
for(int i=0;i<g[u].size();i++){
v=g[u][i];
DFS(v);
sum+=t[v].w;
}
if((sum&1)!=t[u].w&&u){
int p1=pos[t[g[u][0]].r];
int p2=pos[t[g[u][1]].l];
swap(p[p1],p[p2]);
swap(pos[t[g[u][0]].r],pos[t[g[u][1]].l]);
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
int cnt=0;
for(int i=1;i<=m;i++){
cnt++;
cin>>t[cnt].l>>t[cnt].r>>t[cnt].w;
if(t[cnt].l==t[cnt].r&&t[cnt].w==1)flag=1;
if(t[cnt].l==t[cnt].r) cnt--;
}
if(flag){
cout<<"-1"<<"\n";
return 0;
}
for(int i=1;i<=n;i++) {
pos[i]=p[i]=i;
t[++cnt].l=i; t[cnt].r=i; t[cnt].w=0;
}
fa[0]=0; t[0].l=1; t[0].r=n; t[0].w=0;
sort(t+1,t+1+cnt,Cmp);
for(int i=0;i<cnt;i++){
if(t[i].l<=t[i+1].l&&t[i+1].r<=t[i].r){
g[i].push_back(i+1);
fa[i+1]=i;
} else{
int now;
now=i;
while(t[now].r<t[i+1].l){
now=fa[now];
}
g[now].push_back(i+1);
fa[i+1]=now;
}
}
DFS(0);
for(int i=1;i<=n;i++){
cout<<p[i]<<" ";
}
cout<<"\n";
}