AT_abc237_g [ABC237G] Range Sort Query 题解

题目传送门

前置知识

珂朵莉树/颜色段均摊

解法

观察到只有 \(=x\) 的位置才是重要的,而其他位置上的数具体是什么并不重要,我们只需要关注其大小关系。

第一遍将 \(\ge x\) 的数看做 \(1\),将 \(<x\) 的数看做 \(0\)。第二遍将 \(>x\) 的数看做 \(1\),将 \(\le x\) 的数看做 \(1\)

此时排序操作就容易通过查询 \(1\) 的个数后进行推平来维护了,可以使用珂朵莉树/线段树实现。

查询时只需要找到一个位置使得第一遍中是 \(1\) 而第二遍中是 \(0\)

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
int a[200010],b[200010],c[200010];
struct ODT
{
	struct node
	{
		int l,r;
		mutable int col;
		bool operator < (const node &another) const
		{
			return l<another.l;
		}
	};
	set<node>s;
	void init(int n,int a[])
	{
		for(int i=1;i<=n;i++)
		{
			s.insert((node){i,i,a[i]});
		}
	}
	set<node>::iterator split(int pos)
	{
		set<node>::iterator it=s.lower_bound((node){pos,0,0});
		if(it!=s.end()&&it->l==pos)
		{
			return it;
		}
		it--;
		if(it->r<pos)
		{
			return s.end();
		}
		int l=it->l,r=it->r,col=it->col;
		s.erase(it);
		s.insert((node){l,pos-1,col});
		return s.insert((node){pos,r,col}).first;
	}
	void assign(int l,int r,int col)
	{
		set<node>::iterator itr=split(r+1),itl=split(l);
		s.erase(itl,itr);
		s.insert((node){l,r,col});
	}
	int query(int l,int r)
	{
		set<node>::iterator itr=split(r+1),itl=split(l);
		int ans=0;
		for(set<node>::iterator it=itl;it!=itr;it++)
		{
			ans+=it->col*(it->r-it->l+1);
		}
		return ans;
	}
	int ask(int pos)
	{
		set<node>::iterator it=s.lower_bound((node){pos,0,0});
		if(it!=s.end()&&it->l==pos)
		{
			return it->col;
		}
		it--;
		return it->col;
	}
}O[2];
int main()
{
// #define Isaac
#ifdef Isaac
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
#endif
	int n,m,x,pd,l,r,i,j;
	cin>>n>>m>>x;
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
		b[i]=(a[i]>=x);
		c[i]=(a[i]>x);
	}
	O[0].init(n,b);
	O[1].init(n,c);
	for(i=1;i<=m;i++)
	{
		cin>>pd>>l>>r;
		if(pd==1)
		{
			for(j=0;j<=1;j++)
			{
				pd=O[j].query(l,r);
				O[j].assign(l,r-pd,0);
				O[j].assign(r-pd+1,r,1);
			}
		}
		else
		{
			for(j=0;j<=1;j++)
			{
				pd=O[j].query(l,r);
				O[j].assign(l,l+pd-1,1);
				O[j].assign(l+pd,r,0);
			}
		}
	}
	for(i=1;i<=n;i++)
	{
		if(O[0].ask(i)==1&&O[1].ask(i)==0)
		{
			cout<<i<<endl;
		}
	}
	return 0;
}
posted @ 2024-12-30 11:34  hzoi_Shadow  阅读(24)  评论(5编辑  收藏  举报
扩大
缩小