【线段树区间更新】2018CCPC-Wannafly Winter Camp Day5 Div1 I

https://www.zhixincode.com/contest/20/problem/I?problem_id=304

Sorting

已经提交已经通过

46.43%

Total Submission:28

Total Accepted:13

题目描述

 

你有一个数列a1,a2,…,ana_1, a_2, \dots, a_na1​,a2​,…,an​,你要模拟一个类似于快速排序的过程。有一个固定的数字xxx。

你要支持三种操作:

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

输入描述

 

第一行三个整数n,q,x(1≤n,q≤2∗105,0≤x≤109)n, q, x ( 1\leq n, q \leq 2*10^5, 0\leq x\leq 10^9)n,q,x(1≤n,q≤2∗105,0≤x≤109)表示元素的个数和询问的个数。

接下来一行nnn个整数a1,a2,…,an(1≤ai≤109)a_1, a_2, \dots, a_n(1\leq a_i\leq 10^9)a1​,a2​,…,an​(1≤ai​≤109)。

接下来qqq行,每行三个正整数p,l,r(1≤p≤3),1≤l≤r≤np, l, r (1\leq p\leq 3), 1\leq l\leq r\leq np,l,r(1≤p≤3),1≤l≤r≤n表示操作种类和区间。

输出描述

 

对于每个第一种操作,输出一行,表示答案。

样例输入 1

5 9 3
1 5 3 2 4
1 1 5
2 1 5
1 1 1
1 2 2
1 3 3
1 4 4
1 5 5
3 3 5
1 1 4

样例输出 1

15
1
3
2
5
4
13
交换后 ≤x的数 之间相对位置不变, >x的数 之间相对位置也不变
分别记为 0 / 1
1 线段树上查询区间和 对应回原串中的数
2/3 查询 [l, r] 区间和为 x 后区间更新 [l, l + x - 1]、[l + x, r]

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mn = 2e5 + 10;
struct node
{
	int l, r, s, lazy;
} t[8 * mn];

int n, q;
ll x;
ll xiao[mn], da[mn];
int xs, ds;

void build(int id, int l, int r)
{
	t[id].l = l, t[id].r = r;
	t[id].lazy = 2;
	if (l == r)
	{
		ll tt;
		scanf("%lld", &tt);

		t[id].s = (tt <= x) ? 0 : 1;

		if (tt <= x)
			++xs, xiao[xs] = xiao[xs - 1] + tt;
		else
			++ds, da[ds] = da[ds - 1] + tt;

		return;
	}
	int mid = (l + r) >> 1;
	build(2 * id, l, mid);
	build(2 * id + 1, mid + 1, r);
	t[id].s = t[id * 2].s + t[id * 2 + 1].s;
}

void pushdown(int id, int l, int r)
{
	int mid = (l + r) >> 1;
	t[2 * id].lazy = t[id].lazy;
	t[2 * id + 1].lazy = t[id].lazy;
	t[2 * id].s = t[id].lazy * (mid - l + 1);
	t[2 * id + 1].s = t[id].lazy * (r - mid);
    t[id].lazy = 2;
}

void update(int id, int l, int r, int to)
{
	if (r < l)
		return;
	if (l <= t[id].l && r >= t[id].r)
	{
        t[id].lazy = to;
        t[id].s = to * (r - l + 1);
        return;
	}

	if (t[id].lazy != 2)
		pushdown(id, t[id].l, t[id].r);

	int mid = (t[id].l + t[id].r) >> 1;
	if (r <= mid)
		update(2 * id, l, r, to);
	else if (l > mid)
		update(2 * id + 1, l, r, to);
	else
		update(2 * id, l, mid, to), update(2 * id + 1, mid + 1, r, to);

	t[id].s = t[id * 2].s + t[id * 2 + 1].s;
}

int query(int id, int x, int y)
{
	if (y < x)
		return 0;
	if (x == t[id].l && y == t[id].r)
		return t[id].s;

	if (t[id].lazy != 2)
		pushdown(id, t[id].l, t[id].r);

	int mid = (t[id].l + t[id].r) >> 1;
	if (y <= mid)
		return query(2 * id, x, y);
	else if (x > mid)
		return query(2 * id + 1, x, y);
	else
		return query(2 * id, x, mid) + query(2 * id + 1, mid + 1, y);
}

int main()
{
	scanf("%d %d %lld", &n, &q, &x);
	build(1, 1, n);

	int p, l, r;
	while (q--)
	{
		scanf("%d %d %d", &p, &l, &r);
		if (p == 1)
		{
			int r1 = query(1, 1, r), r0 = r - r1;
			int l1 = query(1, 1, l - 1), l0 = l - 1 - l1;
			printf("%lld\n", da[r1] - da[l1] + xiao[r0] - xiao[l0]);
		}
		else
		{
			int x = query(1, l, r);
			if (p == 2)
				update(1, l, r - x, 0), update(1, r - x + 1, r, 1);
			else if (p == 3)
				update(1, l, l + x - 1, 1), update(1, l + x, r, 0);
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值