【luogu P5494】【模板】线段树分裂(线段树合并)(线段树分裂)

【模板】线段树分裂

题目链接:luogu P5494

题目大意

一开始给你第一个可重集,然后它在 1~n 的范围内,然后初始每个数有一定的个数。
然后给你一些操作:
给某个可重集放几个某个数字;询问某个可重集有多少个数在 l~r 之间;询问某个可重集第 k 小的数(如果没有就是 -1);将某个可重集的数全部放入另一个可重集中,并清空它(保证之后都不会用到它);将一个可重集的 l~r 之间的数字全部放入一个新的可重集中,这个可重集的编号是当前可重集的个数。
请维护。

思路

很明显,我们只需要知道如何线段树合并和线段树分裂。

首先是线段树合并,它其实就是你只要把两个线段树同时从根节点开始跑,然后如果两个的某个位置都有值就合并,然后继续分别跑儿子。
有其中一个没有值或两个都没有就返回剩下有的那个或者空。

接着是线段树分裂,线段树分裂我们其实可以参考无旋 Treap 的分裂方式。
其实就是看分割的位置。
如果当前用作分割的第 k 大在左边(根据左儿子大小判断),那说明右边都是给第二个线段树的,然后左边继续分割。
如果在右边,说明左边都是给第一个线段树的,然后右边继续分割。
然后就可以啦。

代码

#include<cstdio>
#include<algorithm>
#define ll long long

using namespace std;

struct node {
   
	int l, r;
	ll x;
}t[200001 << 6];
int n, m, rt[200001];
int bin[200001 << 6], tot, tmp;
int op, x, y, z;

int get_new() {
   
	if (!bin[0]) return ++tot;
	return bin[bin[0]--];
}

void clear(int now) {
   //回收空间
	bin[++bin[0]] = now;
	t[now].l = t[now].r = 0;
	t[now].x = 0;
}

void add(int &now, int l, int r, int pl, ll val) {
   
	if (!now) now = get_new();
	t
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值