2023牛客多校第五场 E. Red and Blue and Green

文章目录

  • 题目大意
  • 题解
      • 并列
      • 包容
  • 参考代码
  • 总结

题目大意

有大小为 n ( 1 ≤ n ≤ 1 0 3 ) n(1 \leq n \leq 10^3) n(1n103) 的未知排列 p p p m ( 1 ≤ m ≤ 1 0 3 ) m(1 \leq m \leq 10^3) m(1m103) 个不同的区间,第 i i i 个区间是 [ l i , r i ] [l_i , r_i] [li,ri] 。保证对于任意两个区间 i , j i,j i,j ,若 l i ≤ l j l_i \leq l_j lilj ,则 r i ≤ r j r_i \leq r_j rirj r i > r j r_i > r_j ri>rj
m m m 条限制,第 i i i 条限制是区间 [ l i , r i ] [l_i,r_i] [li,ri] 内的逆序数对必须是奇数/偶数个。
求满足条件的排列 p p p ,若不存在输出 − 1 -1 1

题解

本题要求的逆序数对个数奇偶性。

考虑一个子区间中:
1.原排列逆序数对数为 0 0 0
2.再随机交换两个数的位置则其逆序数对数为 1 1 1

由题意可知,每两个区间的关系是“包含”或“并列”。
如果想要表示其从属关系,那么用树再好不过了。

并列

容易看出,当两个区间并列时,其逆序数对个数互不影响。

包容

一个大区间中逆序数对数为所有子区间个数之和。
我们可以通过DFS顺序建树来统计子节点中的逆序数对总数。
如果个数奇偶性不同,则只要再加一个逆序数对即可。

考虑如何增加一个逆序数对:
新增 n n n 个区间 ( i , i , 0 ) (i,i,0) (i,i,0)
若不为叶节点,则其中必有两个及以上子节点,
我们灵机一动,想到交换第一个区间的最大值和第二个区间的最小值,
则既不会影响相对位置,又能改变结果。

参考代码

#include
using namespace std;
const int N=3e3+5;
vector<int> son[N];
struct node{
    int l,r,w,l1,r1;
}f[N];
int n,m,root,t;
int vis[N],pos[N];
int fa[N];
int g[N];
int q[2000][2000][3];
int cmp(node a,node b)
{
    if(a.l==b.l)
        return a.r>b.r;
    return a.l<b.l;
}
void dfs(int x)
{
    vis[x]=1;
    int sum=0,ans=0;
    for(int j=x+1;j<=n+t&&f[j].r<=f[x].r;j++)     //在左端点排序的前提下,原顺序就是dfs序列
    {                                              //观察一下右端点位置即可得出相对关系
    	if(!vis[j])
        {
            son[x].push_back(j);
            sum++;
            if(j+1<=n+t && f[j].r>=f[j+1].r)
            	dfs(j);
			vis[j]=1;                 
            ans^=f[j].w;
        }
	}
    if(ans!=f[x].w)
    {
    	int maxx=0,id=0;
        for(int i=f[son[x][0]].l;i<=f[son[x][0]].r;i++)         //暴力求解最大值和最小值
        	if(pos[i]>maxx)
        		maxx=pos[i],id=i;
        int minn=n+1,it=0;
        for(int i=f[son[x][1]].l;i<=f[son[x][1]].r;i++)
        	if(pos[i]<minn)
        		minn=pos[i],it=i;
        swap(pos[id],pos[it]);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int b=0;
	t=0;
    for(int i=1;i<=m;i++)
    {
    	t++;
        scanf("%d%d%d",&f[t].l,&f[t].r,&f[t].w);
        f[t].l1=f[t].l;
        f[t].r1=f[t].r;
        if(f[t].r-f[t].l==0)
        {
            if(f[t].w==1)
                b=1;
            t--;
        }
    }
    if(b)
    {
        puts("-1");
        return 0;
    }
    for(int i=1;i<=n;i++)
        f[++t]={i,i,0,i,i};
    sort(f+1,f+t+1,cmp);
    for(int i=1;i<=n;i++)
        pos[i]=i;
    for(int i=1;i<=n+t;i++)
    {
        if(!vis[i])
            dfs(i);
    }
    for(int i=1;i<=n;i++)
        printf("%d ",pos[i]);
}

总结

1 0 3 10^3 103 的数据给了它任性的理由,
只要能想到建树和区间的特点,这题就能解决了。

你可能感兴趣的:(c++)