BZOJ 3217 ALOEXT 替罪羊树套Trie树

题目大意:维护一个序列,支持以下操作:

1.在某个位置插入一个数

2.删除某个位置上的数

3.修改某个位置上的数

4.求某段区间中的次大值与区间中另一个数的异或值的最大值

强制在线

替罪羊树套Trie树。。。终于尼玛A了。。。7.4KB的大代码啊- -

插入和修改同带插入区间k小值 删除要打标记不能直接删

删除的时候注意 删除导致的不平衡不要重建 否则复杂度无法保证

因此每个节点维护一个max_size代表历史size最大值 判断不平衡时用这个变量来判断即可

注意访问替罪羊树的时候一定要判断当前节点是否已被删除- - 否则问题大大的- -

询问时先找到次小值 然后找异或的最大值 注意不要二分 直接在替罪羊树上找对应区间 具体写法详见代码(如果能找到函数在哪里的话- -)

还有啥注意事项。。。 变量重名,成员函数访问错误,友元函数不引用本结构体指针,失效的默认值,忘记重载delete。。。我也是醉了

尼玛万恶的360把我家的渣渣C-Free给杀了- - 调试功能爆炸了,只能gdb- - 调过样例之后就没心情再调了- -

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
#define L (1<<15)
#define ALPHA 0.88
using namespace std;

class Trie *null;

class Trie{
private:
	static queue<Trie*> bin;
public:
	Trie *son[2];
	int size;
	void* operator new (size_t,Trie *_,Trie *__,int ___)
	{
		static Trie *mempool,*C=mempool;
		Trie *re;
		if( !bin.empty() )
			re=bin.front(),bin.pop();
		else
		{
			if(C==mempool)
				mempool=(C=new Trie[L])+L;
			re=C++;
		}
		re->son[0]=_;
		re->son[1]=__;
		re->size=___;
		return re;
	}
	void operator delete (void *p)
	{
		bin.push((Trie*)p);
	}
	friend void Insert(Trie* &p,int num,int pos=1<<20)
	{
		if(p==null)
			p=new (null,null,0) Trie;
		p->size++;
		if(!pos) return ;
		if(num&pos)
			Insert(p->son[1],num,pos>>1);
		else
			Insert(p->son[0],num,pos>>1);

	}
	void Delete(int num,int pos=1<<20)
	{
		size--;
		if(!pos) return ;
		if(num&pos)
			son[1]->Delete(num,pos>>1);
		else
			son[0]->Delete(num,pos>>1);
	}
	int Get_Kth(int pos,int k)
	{
		if(!pos) return 0;
		if(k<=son[1]->size)
			return pos|son[1]->Get_Kth(pos>>1,k);
		else
			return son[0]->Get_Kth(pos>>1,k-son[1]->size);
	}
	int Get_Max(int pos,int x)
	{
		int temp=pos&x?1:0;
		if(!pos) return 0;
		if(son[!temp]->size)
			return pos|son[!temp]->Get_Max(pos>>1,x);
		else
			return son[temp]->Get_Max(pos>>1,x);
	}
	void Decomposition()
	{
		if(this==null)
			return ;
		son[0]->Decomposition();
		son[1]->Decomposition();
		delete this;
	}
};

class Kth_Getter{
private:
	int first,second;
public:
	Kth_Getter():first(-1),second(-1) {}
	bool Insert(int x)
	{
		if(x>first)
		{
			second=first;
			first=x;
			return true;
		}
		if(x>second)
			second=x;
		return false;
	}
	int Second()
	{
		return second;
	}
};

class Scapetree *nil,**to_rebuild;
int to_delete;

class Scapetree{
private:
	static queue<Scapetree*> bin;
public:
	static int stack[M],top;

	Scapetree *ls,*rs;
	int val,size,max_size;
	Trie *tree;

	void* operator new (size_t,Scapetree *_,Scapetree *__,int ___,int ____)
	{
		static Scapetree *mempool,*C=mempool;
		Scapetree *re;
		if( !bin.empty() )
			re=bin.front(),bin.pop();
		else
		{
			if(C==mempool)
				mempool=(C=new Scapetree[L])+L;
			re=C++;
		}
		re->ls=_;
		re->rs=__;
		re->val=___;
		re->size=____;
		re->max_size=____;
		re->tree=null;
		return re;
	}
	void operator delete (void *p)
	{
		bin.push((Scapetree*)p);
	}
	bool Check()
	{
		if((double)ls->max_size/max_size>ALPHA)
			return true;
		if((double)rs->max_size/max_size>ALPHA)
			return true;
		return false;
	}
	friend void Insert(Scapetree* &p,int pos,int val)
	{
		int temp=~p->val?1:0;
		if(p==nil)
		{
			p=new (nil,nil,val,1) Scapetree;
			Insert(p->tree,val);
			return ;
		}
		p->size++;Insert(p->tree,val);
		p->max_size=max(p->max_size,p->size);
		if(pos<=p->ls->size)
			Insert(p->ls,pos,val);
		else
			Insert(p->rs,pos-p->ls->size-temp,val);
		if(p->Check())
			to_rebuild=&p;
	}
	void Delete(int pos)
	{
		int temp=~val?1:0;
		if(pos<=ls->size)
			ls->Delete(pos);
		else
		{
			pos-=ls->size;
			if(pos==temp)
			{
				to_delete=val;
				val=-1;
			}
			else rs->Delete(pos-temp);
		}
		size--;tree->Delete(to_delete);
	}
	void Modify(int pos,int val)
	{
		int temp=~this->val?1:0;
		if(pos<=ls->size)
			ls->Modify(pos,val);
		else
		{
			pos-=ls->size;
			if(pos==temp)
			{
				to_delete=Scapetree::val;
				Scapetree::val=val;
			}
			else rs->Modify(pos-temp,val);
		}
		tree->Delete(to_delete);
		Insert(tree,val);
	}
	void Decomposition()
	{
		if(this==nil)
			return ;
		ls->Decomposition();
		if(~val) stack[++top]=val;
		rs->Decomposition();
		tree->Decomposition();
		delete(this);
	}
	void Get_2th(int l,int r,Kth_Getter& getter)
	{
		if( l==1 && r==size )
		{
			if( getter.Insert( tree->Get_Kth(1<<20,1) ) && size>=2 )
				getter.Insert( tree->Get_Kth(1<<20,2) );
			return ;
		}
		int temp=~val?1:0;
		if( temp && l<=ls->size+1 && r>=ls->size+1 )
			getter.Insert(val);
		if( l<=ls->size )
			ls->Get_2th(l,min(r,ls->size),getter);
		if( r>ls->size+temp )
			rs->Get_2th(max(l-(ls->size+temp),1),r-(ls->size+temp),getter);
	}
	int Get_Max(int l,int r,int val)
	{
		if( l==1 && r==size )
			return tree->Get_Max(1<<20,val);
		int re=-1,temp=~this->val?1:0;
		if( temp && l<=ls->size+1 && r>=ls->size+1 )
			re=max(re,val^this->val);
		if( l<=ls->size )
			re=max(re,ls->Get_Max(l,min(r,ls->size),val) );
		if( r>ls->size+temp )
			re=max(re,rs->Get_Max(max(l-(ls->size+temp),1),r-(ls->size+temp),val) );
		return re;
	}
	void Output()
	{
		if(this==nil)
			return ;
		ls->Output();
		printf("----------------    %d\n",val);
		rs->Output();
	}
}*root=nil;

Scapetree* Build_Tree(int a[],int l,int r)
{
	if(l>r) return nil;
	int i,mid=l+r>>1;
	Scapetree *lson=Build_Tree(a,l,mid-1);
	Scapetree *rson=Build_Tree(a,mid+1,r);
	Scapetree *re=new (lson,rson,a[mid],r-l+1) Scapetree;
	for(i=l;i<=r;i++)
		Insert(re->tree,a[i]);
	return re;
}

queue<Trie*> Trie :: bin;
queue<Scapetree*> Scapetree :: bin;
int Scapetree :: stack[M];
int Scapetree :: top;

int n,m,last_ans;
int a[M>>1];

void Initialize()
{
	null=new (0x0,0x0,0) Trie;
	null->son[0]=null->son[1]=null;
	nil=new (0x0,0x0,0,0) Scapetree;
	nil->ls=nil->rs=nil;
}

void Insert(int pos,int val)
{
	to_rebuild=0x0;
	Insert(root,pos,val);
	if(to_rebuild)
	{
		Scapetree::top=0;
		(*to_rebuild)->Decomposition();
		(*to_rebuild)=Build_Tree(Scapetree::stack,1,Scapetree::top);
	}
}

int Query(int l,int r)
{
	Kth_Getter getter;
	root->Get_2th(l,r,getter);
	int val=getter.Second();
	return root->Get_Max(l,r,val);
}

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("3217.in","r",stdin);
	freopen("3217.out","w",stdout);
	#endif

	int i,x,y;
	char p[100];
	Initialize();
	cin>>n>>m;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	root=Build_Tree(a,1,n);
	for(i=1;i<=m;i++)
	{
		scanf("%s",p);
		switch(p[0])
		{
			case 'I':
				scanf("%d%d",&x,&y);
				x=(x+last_ans)%(n++);
				y=(y+last_ans)%1048576;
				Insert(x,y);
				break;
			case 'D':
				scanf("%d",&x);
				x=(x+last_ans)%n+1;
				root->Delete(x);
				n--;
				break;
			case 'C':
				scanf("%d%d",&x,&y);
				x=(x+last_ans)%n+1;
				y=(y+last_ans)%1048576;
				root->Modify(x,y);
				break;
			case 'F':
				scanf("%d%d",&x,&y);
				x=(x+last_ans)%n+1;
				y=(y+last_ans)%n+1;
				if(x>y) swap(x,y);
				printf("%d\n", last_ans=Query(x,y) );
				break;
		}
		//root->Output();puts("");
	}
	return 0;
}
时间: 2024-10-10 03:47:47

BZOJ 3217 ALOEXT 替罪羊树套Trie树的相关文章

【bzoj3217】ALOEXT 替罪羊树套Trie树

题目描述 taorunz平时最喜欢的东西就是可移动存储器了……只要看到别人的可移动存储器,他总是用尽一切办法把它里面的东西弄到手. 突然有一天,taorunz来到了一个密室,里面放着一排可移动存储器,存储器里有非常珍贵的OI资料……不过比较特殊的是,每个存储器上都写着一个非负整数.taorunz很高兴,要把所有的存储器都拿走(taorunz的智商高达500,他一旦弄走了这里的所有存储器,在不久到来的AHOI和NOI中……你懂的).不过这时有一个声音传来:“你只能拿走这里的一个存储器,而且还不能直

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin

HDU - 5390 tree 线段树套字典树 (看题解)

HDU - 5390 看到的第一感觉就是树链剖分 + 线段树套字典树, 感觉复杂度不太对. 其实这种路径其实很特殊, 一个点改变只会影响它儿子到根的路径, 并且这种求最优值问题可以叠加. 所以我们修改的时候对对应dfs序打标记, 询问的时候在线段树上从上往下对每个对应区间求个最优值. 这样还会被卡MLE.. 需要分层优化一下. #pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL l

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

AVL树,红黑树,B-B+树,Trie树原理和应用

前言:本文章来源于我在知乎上回答的一个问题 AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中? 看完后您可能会了解到这些数据结构大致的原理及为什么用在这些场景,文章并不涉及具体操作(如插入删除等等) 目录 AVL树 AVL树原理与应用 红黑树 红黑树原理与应用 B/B+树 B/B+树原理与应用 Trie树 Trie树原理与应用 AVL树 简介: AVL树是最早的自平衡二叉树,在早期应用还相对来说比较广,后期由于旋转次数过多而被红黑树等结构取代(二者都是用来搜索的),AVL树内

查找(二)简单清晰的B树、Trie树具体解释

查找(二) 散列表 散列表是普通数组概念的推广.因为对普通数组能够直接寻址,使得能在O(1)时间内訪问数组中的任何位置.在散列表中,不是直接把keyword作为数组的下标,而是依据keyword计算出对应的下标. 使用散列的查找算法分为两步.第一步是用散列函数将被查找的键转化为数组的一个索引. 我们须要面对两个或多个键都会散列到同样的索引值的情况.因此,第二步就是一个处理碰撞冲突的过程,由两种经典解决碰撞的方法:拉链法和线性探測法. 散列表是算法在时间和空间上作出权衡的经典样例. 假设没有内存限

【vijos】1750 建房子(线段树套线段树+前缀和)

https://vijos.org/p/1750 是不是我想复杂了.... 自己yy了个二维线段树,然后愉快的敲打. 但是wa了两法.......sad 原因是在处理第二维的更新出现了个小问题,sad. void pushup1(int x) { for1(i, 1, mm<<2) mn[x][i]=min(mn[lc][i], mn[rc][i]); } 这里注意是mm*4...我该好好想想了..这是在dbg的时候找出来的问题.sad. 我觉得很奇怪,线段树的底层节点一共就mm个,那么整棵树

【bzoj4785】[Zjoi2017]树状数组 线段树套线段树

题目描述 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1) mod 2. 2 l r,表示询问 sigma(Ai) mod 2,L<=i<=r 尽管那个时候的可怜非常的 simple,但是她还是发现这题可以用树状数组做.当时非常young 的她写了如下的算法: 1: function Add(x

查找(二)简单清晰的B树、Trie树详解

查找(二) 散列表 散列表是普通数组概念的推广.由于对普通数组可以直接寻址,使得能在O(1)时间内访问数组中的任意位置.在散列表中,不是直接把关键字作为数组的下标,而是根据关键字计算出相应的下标. 使用散列的查找算法分为两步.第一步是用散列函数将被查找的键转化为数组的一个索引. 我们需要面对两个或多个键都会散列到相同的索引值的情况.因此,第二步就是一个处理碰撞冲突的过程,由两种经典解决碰撞的方法:拉链法和线性探测法. 散列表是算法在时间和空间上作出权衡的经典例子. 如果没有内存限制,我们可以直接