BZOJ 3065 带插入区间K小值 替罪羊树套线段树

38 篇文章 0 订阅
9 篇文章 0 订阅

题目大意:带插入、修改的区间k小值

我也作死去学了下替罪羊树(OTZ HZWER)……之前在想平衡树套不了线段树看到这题直接秒收弗拉格啊

普通的平衡树由于有旋转操作 所以如果每旋转一次都重建一次平衡树妥妥TLE 但是替罪羊树就没什么问题 因为替罪羊树没有旋转

如果一个节点的某个儿子的size超过了本身size的55%~80% 就暴力重建这棵子树 这个节点就被称作替罪羊节点

个人对“替罪羊”的理解就是“明明是我的儿子过大为什么要把我重建啊QAQ”啥的……

于是我们每次插入时都把所有需要重建的替罪羊节点压到一个栈里 然后取深度最小的那个进行重建

无视代码里那变态的封装吧…… 记得写垃圾回收不然会挂

各种封装各种重载new重载delete啥的各种写不明白搞了一下午……最后交上去1A我也是醉了……HZWER究竟为何能写的那么短……

最后虽然出题人让我们自行nlog^2n但是我还是作死写了nlog^3n……懒得改了


#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 70700
#define ALPHA 0.8
using namespace std;
struct Segtree{
	Segtree *ls,*rs;
	int num;
	void* operator new (size_t size);
	void operator delete (void* p);
	void Insert(int x,int y,int val);
	void Delete(int x,int y,int val);
	int Get_Ans(int x,int y,int val);
	void Decomposition();
}*mempool,*C;
struct abcd{
	abcd *ls,*rs;
	int num,size;
	Segtree* tree;
	void* operator new (size_t size,int x);
	void operator delete (void *p);
	void Maintain();
	void Decomposition();
	bool Check();
}*root,*_mempool,*G;
queue<void*>bin[2];
int n,m,ans,a[M],tot;
abcd **stack[M];int top;
int changed_num;
void* Segtree :: operator new (size_t size)
{
	if( !bin[0].empty() )
	{
		void *re=bin[0].front();
		bin[0].pop();
		memset(re,0,sizeof(Segtree) );
		return re;
	}
	if(C==mempool)
	{
		C=new Segtree[1<<15];
		mempool=C+(1<<15);
		memset(C,0,sizeof(Segtree)*(1<<15) );
	}
	return C++;
}
void Segtree :: operator delete (void *p)
{
	bin[0].push(p);
}
void Segtree :: Insert(int x,int y,int val)
{
	int mid=(x+y)>>1;
	num++;
	if(x==y)
		return ;
	if(val<=mid)
	{
		if(!ls) ls=new Segtree;
		ls->Insert(x,mid,val);
	}
	else
	{
		if(!rs) rs=new Segtree;
		rs->Insert(mid+1,y,val);
	}
}
void Segtree :: Delete(int x,int y,int val)
{
	int mid=(x+y)>>1;
	num--;
	if(x==y)
		return ;
	if(val<=mid)
		ls->Delete(x,mid,val);
	else
		rs->Delete(mid+1,y,val);
}
int Segtree :: Get_Ans(int x,int y,int val)
{
	int mid=(x+y)>>1;
	if(!num) return 0;
	if(x==y) return num;
	if(val<=mid)
		return ls?ls->Get_Ans(x,mid,val):0;
	else
		return (ls?ls->num:0) + 
				(rs?rs->Get_Ans(mid+1,y,val):0);
}
void Segtree :: Decomposition()
{
	if(ls) ls->Decomposition();
	if(rs) rs->Decomposition();
	delete this;
}
void* abcd :: operator new (size_t size,int x)
{
	if( !bin[1].empty() )
	{
		abcd *re=(abcd*)bin[1].front();
		bin[1].pop();
		re->ls=re->rs=0x0;
		re->num=x;re->size=1;
		re->tree=new Segtree;
		return re;
	}
	if(G==_mempool)
	{
		G=new abcd[1<<15];
		_mempool=G+(1<<15);
		memset(G,0,sizeof(abcd)*(1<<15) );
	}
	G->ls=G->rs=0x0;
	G->num=x;G->size=1;
	G->tree=new Segtree;
	return G++;
}
void abcd :: operator delete (void *p)
{
	bin[1].push(p);
}
void abcd :: Maintain()
{
	size=1;
	if(ls) size+=ls->size;
	if(rs) size+=rs->size;
}
void abcd :: Decomposition()
{
	if(ls) ls->Decomposition();
	a[++tot]=num;
	if(rs) rs->Decomposition();
	tree->Decomposition();
	delete this;
}
abcd* Build_Tree(int x,int y)
{
	int i;
	if(x>y) return 0x0;
	int mid=(x+y)>>1;
	abcd *re=new (a[mid]) abcd;
	re->ls=Build_Tree(x,mid-1);
	re->rs=Build_Tree(mid+1,y);
	for(i=x;i<=y;i++)
		re->tree->Insert(0,70000,a[i]);
	return re->Maintain(),re;
}
void Rebuild(abcd *&x)
{
	top=0;tot=0;
	x->Decomposition();
	x=Build_Tree(1,tot);
}
bool abcd :: Check()
{
	static double rate;
	if(ls)
	{
		rate=ls->size*1.0/size;
		if(rate>ALPHA)
			return true;
	}
	if(rs)
	{
		rate=rs->size*1.0/size;
		if(rate>ALPHA)
			return true;
	}
	return false;
}
void Insert(abcd *&x,int y,int z)
{
	if(!x)
	{
		x=new (z) abcd;
		x->tree->Insert(0,70000,z);
		return;
	}
	x->tree->Insert(0,70000,z);
	int temp=x->ls?x->ls->size:0;
	if(y<=temp)
	{
		Insert(x->ls,y,z);
		if( x->ls->Check() )
			stack[++top]=&x->ls;
	}
	else
	{
		Insert( x->rs,y-temp-1,z );
		if( x->rs->Check() )
			stack[++top]=&x->rs;
	}
	x->Maintain();
}
int Get_Lesser(abcd *x,int y,int z)
{
	int re=0,temp=x->ls?x->ls->size:0;
	if(!y) return 0;
	if(y<=temp)
		return Get_Lesser(x->ls,y,z);
	y-=temp;
	if(x->ls)
		re+=x->ls->tree->Get_Ans(0,70000,z);
	y--;re+=(x->num<=z);
	if(!y) return re;
	return re + Get_Lesser(x->rs,y,z);
}
int Query(int x,int y,int k)
{
	int l=0,r=70000;
	while(l+1<r)
	{
		int mid=(l+r)>>1;
		if( Get_Lesser(root,y,mid)-
			Get_Lesser(root,x-1,mid)>=k )
			r=mid;
		else
			l=mid;
	}
	if( Get_Lesser(root,y,l)-
		Get_Lesser(root,x-1,l)>=k )
		return l;
	return r;
}
void Modify(abcd *x,int y,int z)
{
	int temp=x->ls?x->ls->size:0;
	if(y<=temp)
		Modify(x->ls,y,z);
	else if((y-=temp)==1)
		changed_num=x->num,x->num=z;
	else
		Modify(x->rs,--y,z);
	x->tree->Delete(0,70000,changed_num);
	x->tree->Insert(0,70000,z);
}
void Insert(int x,int y)
{
	--x;++n;
	Insert(root,x,y);
	if( root->Check() ) stack[++top]=&root;
	if(top) Rebuild(*stack[top]);
}
void Output(abcd *x)
{
	if(!x) return;
	Output(x->ls);
	printf("======%d\n",x->num);
	Output(x->rs);
}
int main()
{
	int i,x,y,k;
	char p[10];
	cin>>n;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	root=Build_Tree(1,n);
	cin>>m;
	for(i=1;i<=m;i++)
	{
		//Output(root);
		scanf("%s%d%d",p,&x,&y);
		x^=ans;y^=ans;
		switch(p[0])
		{
			case 'Q':
				scanf("%d",&k);k^=ans;
				printf("%d\n",ans=Query(x,y,k) );
				break;
			case 'M':
				Modify(root,x,y);
				break;
			case 'I':
				Insert(x,y);
				break;
		}
	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值