题意:
要求你构造出一个长度为n的全排列,使它满足给出的m个区间 [ li,ri ] 都满足给出的相应的逆序对个数的奇偶性。
题解:
由于给出的区间要么是重合端点包含关系,要么是不相交包含关系。
我们首先将这个全排列处理为1~n的排列。
然后将m个区间从小到大进行排序然后进行更改。
对于两个不相交的区间,我们如果需要更改区间的奇偶性,直接交换这两个区间的最小值和次小值。
对于重合左端点包含关系,我们将先前遍历的与长区间左端点重合的短区间的最大值x,与x+1进行交换,这样交换之后可以证明正确性。假设对于[1,x]的短区间,使它的x与x+1进行交换,对于与他相邻的[x+1,x+m]短区间,在 [1,x]的短区间中将x变成x+1不改变其逆序对,然后对于[x+1,x+m]短区间把x+1改成x也不改变其逆序对,然后对于包含[1,x]的长区间,他的逆序对个数加1,奇偶性改变。
代码:
#include<bits/stdc++.h>
using namespace std;
int i,j,k,n,m,a[200005],nex[2005],p[20005],change[20005];
struct op
{
int l,r,t;
} s[2005];
bool cmp(op x,op y)
{
if (x.r-x.l==y.r-y.l) return x.l<y.l;
return x.r-x.l<y.r-y.l;
}
int main()
{
cin>>n>>m;
for (i=1; i<=n; i++)
{
a[i]=i;
p[i]=i;
nex[i]=i;
}
for (i=1; i<=m; i++)
{
cin>>s[i].l>>s[i].r>>s[i].t;
}
sort(s+1,s+m+1,cmp);//从短区间到长区间枚举
for (i=1; i<=m; i++)
{
if (s[i].l==s[i].r&&s[i].t==1)
{
cout<<-1;
return 0;
}
int cnt=0;
for (j=s[i].l; j<=s[i].r; j++)
{
cnt+=change[j];
}
if (s[i].t!=cnt%2)
{
swap(a[p[nex[s[i].l]]],a[p[nex[s[i].l]+1]]);
swap(p[nex[s[i].l]],p[nex[s[i].l]+1]);
change[s[i].l]++;
}
nex[s[i].l]=s[i].r;
}
for (i=1; i<=n; i++) cout<<a[i]<<' ';
}