suxxsfe

一言(ヒトコト)

P5494 线段树分裂

https://www.luogu.com.cn/problem/P5494

线段树合并在这里:https://www.cnblogs.com/suxxsfe/p/13839555.html

这个分裂其实和 fhq-treap 有点像,就是把一棵树分裂为两棵树,把第一棵树中的 \([l,r]\) 节点分裂到第二个树
过程大概是这样的,设被分裂的树为 \(a\),分裂到 \(b\)

  • 如果 \(a\) 为空,那么肯定直接返回
  • 如果要分裂出的 \([l,r]\) 区间完全覆盖了当前区间,整棵树都应该给 \(b\),也就是 b=a,a=null
  • 根据区间的情况,考虑是否要递归分裂 \(a,b\) 的左右子树
  • 注意两棵树的指针都要传引用

复杂度显然 \(O(\log n)\)
所以也没什么很难的地方

那么看这个题,先建立权值线段树,\(0\) 操作分裂出 \([x,y]\) 到一个新树,\(1\) 操作将整个 \(t\)merge\(p\)\(2,3,4\) 几个操作都是线段树的基本操作了

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN puts("")
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
#define N 400006
int n,m,Now;
struct Node{
	Node *ls,*rs;
	long long cnt;
}dizhi[N*30],*root[N],*null=&dizhi[0];
int tot;
inline void New(Node *&a){
	a=&dizhi[++tot];a->ls=a->rs=null;
}
void change(Node *tree,int l,int r,int pos,int w){
	tree->cnt+=w;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(pos<=mid){
		if(tree->ls==null) New(tree->ls);
		change(tree->ls,l,mid,pos,w);
	}
	else{
		if(tree->rs==null) New(tree->rs);
		change(tree->rs,mid+1,r,pos,w);
	}
}
long long ask(Node *tree,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr) return tree->cnt;
	int mid=(l+r)>>1;
	long long ret=0;
	if(ql<=mid&&tree->ls!=null) ret+=ask(tree->ls,l,mid,ql,qr);
	if(qr>mid&&tree->rs!=null) ret+=ask(tree->rs,mid+1,r,ql,qr);
	return ret;
}
int kth(Node *tree,int l,int r,int k){
	if(l==r) return l;
	int mid=(l+r)>>1;
	if(k<=tree->ls->cnt) return kth(tree->ls,l,mid,k);
	else return kth(tree->rs,mid+1,r,k-tree->ls->cnt);
}
inline void pushup(Node *tree){tree->cnt=tree->ls->cnt+tree->rs->cnt;}
Node *merge(Node *x,Node *y,int l,int r){
	if(x==null) return y;
	if(y==null) return x;
	if(l==r) return x->cnt+=y->cnt,x;
	int mid=(l+r)>>1;
	x->ls=merge(x->ls,y->ls,l,mid);
	x->rs=merge(x->rs,y->rs,mid+1,r);
	pushup(x);
	return x;
}
void split(Node *&a,Node *&b,int l,int r,int ql,int qr){
	if(a==null) return;
	if(ql<=l&&r<=qr) return b=a,a=null,void();//完全覆盖
	if(b==null) New(b);
	int mid=(l+r)>>1;
	if(ql<=mid) split(a->ls,b->ls,l,mid,ql,qr);
	if(qr>mid) split(a->rs,b->rs,mid+1,r,ql,qr);
	pushup(a);pushup(b);
}
int main(){
	n=read();m=read();
	New(root[1]);Now=1;
	for(reg int i=1;i<=n;i++) change(root[1],1,n,i,read());
	reg int k,x,y,op;
	while(m--){
		op=read();
		if(!op){
			k=read();x=read();y=read();
			New(root[++Now]);
			split(root[k],root[Now],1,n,x,y);
		}
		else if(op==1){
			x=read();y=read();
			merge(root[x],root[y],1,n);
		}
		else if(op==2){
			k=read();x=read();y=read();
			change(root[k],1,n,y,x);
		}
		else if(op==3){
			k=read();x=read();y=read();
			printf("%lld\n",ask(root[k],1,n,x,y));
		}
		else{
			x=read();k=read();
			if(root[x]->cnt<k) puts("-1");
			else printf("%d\n",kth(root[x],1,n,k));
		}
	}
	return 0;
}
posted @ 2020-10-19 23:45  suxxsfe  阅读(136)  评论(0编辑  收藏  举报