【Luogu5494】【模板】线段树分裂

[ L i n k \frak{Link} Link]


不开 long long 见祖宗!!


不难发现应该是开多颗权值线段树
感觉像是把线段树拆开?有点类似 Lazytag 那样就不需要处理中间部分
然后外面部分染上你的颜色
其实就是类似主席树那个感觉嘛

口胡 → Wrong Answer


我看见了不开 long long 见祖宗
但我没想到要这么开。。。
虽然我其他地方写的 bug 也不少()
像割完原来的树没 update 啦
不知道 split 了个什么东西啦
没有写垃圾回收啦(说起来我还不会分析这东西的空间复杂度)


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = (200005)<<5;
const int MINN = 200005;
int n, m, tot=0;
int Lc[MAXN], Rc[MAXN];
long long Siz[MAXN];
int Rt[MINN];
int Recy[MAXN<<5];
#define NewPnt ((Recy[0])?Recy[Recy[0]--]:++tot)
#define SegRecycle(Num) {Recy[++Recy[0]]=Num, Siz[Num]=0,Lc[Num]=0,Rc[Num]=0;}
#define SegCopy(ori, niw) {Lc[niw]=Lc[ori],Rc[niw]=Rc[ori],Siz[niw]=Siz[ori];}
#define Update(pos) {Siz[pos]=Siz[Lc[pos]]+Siz[Rc[pos]];}

void Insert(int &Pos, int L, int R, int Val, int Cnt)
{
	if (!Pos) Pos = NewPnt;
	Siz[Pos] += Cnt;
	if (L < R)
	{
		int Mid = L + R >> 1;
		if (Val <= Mid) Insert(Lc[Pos], L, Mid, Val, Cnt);
		else Insert(Rc[Pos], Mid + 1, R, Val, Cnt);
	}
}

void Split(int &Pos, int &Tar, int L, int R, int bordL, int bordR)
{
	if ((!Pos) || L > bordR || R < bordL) return;
	if (L >= bordL && R <= bordR)
	{
		Tar = Pos;
		Pos = 0;
		return;
	}
	int Mid = L + R >> 1;
	Tar = NewPnt;
	Split(Lc[Pos], Lc[Tar], L, Mid, bordL, bordR);
	Split(Rc[Pos], Rc[Tar], Mid + 1, R, bordL, bordR);
	Update(Pos);
	Update(Tar);
}

void Merge(int Pos, int &Tar)
{
//	cout<<Pos<<"*orz*"<<Tar<<endl;
	if (!Pos) return;
	if (!Tar) { Tar = Pos; return;}
	Siz[Tar] += Siz[Pos];
	if (Lc[Pos]) Merge(Lc[Pos], Lc[Tar]);
	if (Rc[Pos]) Merge(Rc[Pos], Rc[Tar]);
	SegRecycle(Pos);  
//	cout<<"*&*"<<Siz[Tar]<<endl;
}

long long Query_num(int Pos, int L, int R, int bordL, int bordR)
{
	if (bordL > R || bordR < L || !Pos) return 0;
	if (L >= bordL && R <= bordR) return Siz[Pos];
	int Mid = L + R >> 1;
	return Query_num(Lc[Pos], L, Mid, bordL, bordR) + Query_num(Rc[Pos], Mid + 1, R, bordL, bordR);
}

int Query_kth(int Pos, int L, int R, long long Kth)
{
	//cout<<Pos<<" "<<L<<" "<<R<<" "<<Kth<<" "<< Siz[Lc[Pos]]<<" "<<Siz[Rc[Pos]]<<"kt\n";
    if (!Pos) return -1;
	if (L == R) return (Kth>=1)?L:-1;
	if (L < R)
	{
		int Mid = L + R >> 1;
		long long SubLef = Kth - Siz[Lc[Pos]];
		if (SubLef > 0) return Query_kth(Rc[Pos], Mid + 1, R, SubLef);
		return Query_kth(Lc[Pos], L, Mid, Kth); 
	}
}

int main()
{	
	scanf("%d%d", &n, &m);
	
	Rt[0] = 1;
	for (register int a, i = 1; i <= n; ++i)
	{
		scanf("%d", &a);
		Insert(Rt[1], 1, n, i, a);
	}
	
	long long rk;
	bool Failed;
	for (register int opt, p, x, y, i = 1; i <= m; ++i)
	{
		scanf("%d", &opt);
		if (opt==4) scanf("%d%lld", &p, &rk);
		else scanf("%d%d", &p, &x);
		if (opt!=1&&opt!=4) scanf("%d", &y);
		
		switch(opt)
		{
			case 0:
				// 0 p x y
				/* Move "all the numbers between p and q in multiset p" to a NEW multiset. */
				Split(Rt[p], Rt[++Rt[0]], 1, n, x, y);
				break;
				
			case 1:
				// 1 p x
				/* Move "all the numbers in multiset x" to multiset p and clear multiset x. */
				Merge(Rt[x], Rt[p]);
				break;
				
			case 2:
				// 2 p x y
				/* add "x y's" to multiset p. */
				Insert(Rt[p], 1, n, y, x);
				break;
				
			case 3:
				// 3 p x y 
				/* QUERY: The number of the elements with values between x and y in multiset p. */
				printf("%lld\n", Query_num(Rt[p], 1, n, x, y));
				break;
				
			case 4:
				// 4 p x
				/* QUERY: The xth-smallest number in multiset p. PRINT "-1" IF IT DOESNT EXIST */
				printf("%d\n", Query_kth(Rt[p], 1, n, rk)); 
				break;
				
			default:break;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值