2018CCPC-Wannafly Winter Camp Day5 [I. Sorting] (非常优秀的题目,十分巧妙的线段树)

先呈上原题链接

这是一道非常优秀的线段的题目,如此说的原因不是因为它的操作有多么新奇,而是因为解该题的思路有着很好的启发作用。

题意:
你有一个数列 a 1 , a 2 , , a n a_1, a_2, \dots, a_n a1,a2,,an ,你要模拟一个类似于快速排序的过程。有一个固定的数字 x x x

你要支持三种操作:

  • 询问区间 [ l , r ] [l, r] [l,r] 之间的元素的和,也就是 i = l r a i \sum_{i=l}^r a_i i=lrai
  • 对区间 [ l , r ] [l,r] [l,r] 进行操作,也就是说你把区间中所有的数字拿出来,然后把小于等于 x x x 的数字按顺序放在左边,把大于 x x x 的数字按顺序放在右边,把这些数字接起来,放回到数列中。比如说 x = 3 x=3 x=3 ,你的区间里的数字是 1 , 5 , 3 , 2 , 4 1,5,3,2,4 1,5,3,2,4,那么操作完之后区间里面的数字变为 1 , 3 , 2 , 5 , 4 1,3,2,5,4 1,3,2,5,4
  • 对区间 [ l , r ] [l,r] [l,r] 进行操作,也就是说你把区间中所有的数字拿出来,然后把大于 x x x 的数字按顺序放在左边,把小于等于 x x x 的数字按顺序放在右边,把这些数字接起来,放回到数列中。

思路:

  • 首先注意到, x x x 是给定的。 所以无论何时,所有小于等于 x x x 的数的相对顺序不会变,所有大于 x x x 的数的相对顺序也不会变。
  • 那么我们把所有大于 x x x 的数看作是 1 1 1 ,把所有小于等于 x x x 的数看作是 0 0 0 ,每一次区间更新前先查询一下该区间有多少个 1 1 1 ,然后就是把区间的前(后)一段赋值为 1 1 1 后(前)一段赋值为 0 0 0 。至此就可以想想查询操作有没有怎么好的性质。
  • 对于区间 [ l , r ] [l,r] [l,r] 查询,我们可以直接查询 [ 1 , l 1 ] [1,l-1] [1,l1] 区间有多少个大于 x x x 的数,即这个区间有多少个 1 1 1 ,再查询 [ 1 , r ] [1,r] [1,r] 区间有多少个大于 x x x 的数。然后因为他们的相对顺序不变,我们就可以知道要查询的 [ l , r ] [l,r] [l,r] 区间内大于 x x x 的数是从第几个起到第几个的了,此时我们只需要维护一个大于 x x x 的数的前缀和就行了。 对于小于等于 x x x 的数同理。
  • 所有该题用线段树加前缀和就能搞定。

坑点:
注意有没有爆范围。。。

good luck and have fun!!!
附上代码:

#include<bits/stdc++.h>
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define test(flag,value) cout<<flag<<":"<<(value)<<endl
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;
const int MAXN=8e5+10;
const int MOD=998244353;
const double PI=acos(-1);

int row[MAXN],sum[MAXN],a[MAXN],lazy[MAXN];
LL pre1[MAXN],pre2[MAXN];
inline void push_up(int rt)
{
	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void push_down(int rt,int l,int r)
{
	if(lazy[rt]==-1) return;
	int m=(l+r)>>1;
	lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
	sum[rt<<1]=lazy[rt]*(m-l+1);
	sum[rt<<1|1]=lazy[rt]*(r-m);
	lazy[rt]=-1;
}
void build(int l,int r,int rt)
{
	if(l==r)
	{
		sum[rt]=a[l];
		return;
	}
	int m=(l+r)>>1;
	build(l,m,rt<<1);
	build(m+1,r,rt<<1|1);
	push_up(rt);
}
void update(int L,int R,int l,int r,int rt,int val)
{
	if(L>R)return;
	if(L<=l&&r<=R)
	{
		sum[rt]=val*(r-l+1);
		lazy[rt]=val;
		return;
	}
	int m=(l+r)>>1;
	push_down(rt,l,r);
	if(m>=L) update(L,R,l,m,rt<<1,val);
	if(m<R)  update(L,R,m+1,r,rt<<1|1,val);
	push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
	if(L>R)return 0;
	if(L<=l&&r<=R)return sum[rt];
	int m=(l+r)>>1;
	push_down(rt,l,r);
	int res=0;
	if(m>=L) res+=query(L,R,l,m,rt<<1);
	if(m<R)  res+=query(L,R,m+1,r,rt<<1|1);
	return res;
}
int main(void)
{
	int n,q,x;
	mem(lazy,-1);
	scanf("%d%d%d",&n,&q,&x);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",row+i);
		if(row[i]>x)
			a[i]=1;
		else a[i]=0;
	}
	build(1,n,1);
	pre1[0]=pre2[0]=0;
	int p1=1,p2=1;
	for(int i=1;i<=n;i++)
	{
		if(a[i]==1)
		{
			pre2[p2]=row[i]+pre2[p2-1];
			p2++;
		}
		else
		{
			pre1[p1]=row[i]+pre1[p1-1];
			p1++;
		}
	}
	while(q--)
	{
		int type,l,r;
		scanf("%d%d%d",&type,&l,&r);
		if(type==1)
		{
			LL ans=0;
			int totr=query(1,r,1,n,1);
			int totl=query(1,l-1,1,n,1);
			LL tot1=pre2[totr]-pre2[totl];
			LL tot0=pre1[r-totr]-pre1[l-1-totl];
			ans=tot1+tot0;
			printf("%lld\n", ans);
		}
		else if(type==2)
		{
			int tot1=query(l,r,1,n,1);
			update(r-tot1+1,r,1,n,1,1);
			update(l,r-tot1,1,n,1,0);
		}
		else if(type==3)
		{
			int tot1=query(l,r,1,n,1);
			update(l,l+tot1-1,1,n,1,1);
			update(l+tot1,r,1,n,1,0);
		}
	}
}
全部评论

相关推荐

2025-12-15 11:27
门头沟学院 Java
哇哇的菜鸡oc:所有人不要理会,就好了,后面他就知道怎么回事了,只能说有的时候市场都是被宰的人搞坏的
点赞 评论 收藏
分享
2025-12-02 02:15
门头沟学院
最近菊厂陆续开了,极力劝退那些拿13级的985硕士,就13级那么点儿薪资,一线城市每个月到手1.8/7/6w,租房2k还是破烂,吃饭2k还是预制菜,买个1k衣服都是聚酯纤维破塑料,稍微出去浪一浪,能留1w就是万岁,要是再有个啥都想买的对象,一线工作一年难存10w。隔壁工地混泥土,钳工,焊工一天800+,还包吃包住。读书18年到985硕士出来就为了进厂螺丝工?还不如从8岁童工开始干活,别人读书完了你工龄18+,混不上领导也是个小头头了。当然专科进来正式工,od都行,一般本科进来13级也OK,毕竟22岁年纪摆在那个地方还不需要太花钱。读硕博的基本26岁,工作两年就要结婚的,兜里没几个崽,连彩礼都要信用贷。菊厂离职的不少,毕竟正常没人受得了9116(梗:再来一次911刷6)。为啥这时候劝?因为刚下班,因为国考刚完,省考下周,就是可惜选调只有当年应届能报。现在回想能拍断大腿。应届生真实好身份,错过这一次,选调,考公,考编,当老师,进医院,研究所,高校,央国企,基本都无缘了,就连报名资格都被剥夺了,可谓是被党和国家遗弃的废材,统称“社会上的”,扔到社会去流浪,被用坏了就扔医院,长期超负载使用,零件修不好基本可以扔火里回炉重造了。体制内奉行找体制内的,都是党和国家选的人才,智力不差,样貌不丑,身材端正,收入稳定,安居房政策福利待遇也OK。因公出行都是报销,周末顺带“游山玩水“,这种体制内单身资源但凡想找对象,去社会上随便吆喝一声都排队。观察一下,基本没什么公务员在相亲,因为早就被邻里邻居抢光了。
哈哈哈,你是老六:就这不去的人大把人干呢,现在不缺人干活,你不干大把干呢,还有那个说农民工赚钱的,那个800+我估计肯定也就那一段时间,哪有这么赚钱,还是一句话,要想存下钱必须花销极低,能省的就不花钱,工资要高点
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务