1. 程式人生 > >BZOJ 3217 ALOEXT 替罪羊樹套Trie樹

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;
}


相關推薦

BZOJ 3217 ALOEXT 替罪羊Trie

題目大意:維護一個序列,支援以下操作: 1.在某個位置插入一個數 2.刪除某個位置上的數 3.修改某個位置上的數 4.求某段區間中的次大值與區間中另一個數的異或值的最大值 強制線上 替罪羊樹套Trie樹。。。終於尼瑪A了。。。7.4KB的大程式碼啊- - 插入和修改同帶插入

【bzoj3217】ALOEXT 替罪羊Trie

uil 重新 return 等於 開始 space 無法 last esp 題目描述 taorunz平時最喜歡的東西就是可移動存儲器了……只要看到別人的可移動存儲器,他總是用盡一切辦法把它裏面的東西弄到手。 突然有一天,taorunz來到了一

BZOJ 4896 [Thusc2016]補退選 (Trie維護vector)

sub names pri 記錄操作 return scanf line code query 題目大意:略 這竟然是$thusc$的題... 先把詢問裏加入的串全拎出來,建出$Trie$樹,$Trie$裏每個節點都開一個$vector$記錄操作標號,再記錄操作數量$s

hdu 6191 可持久化trie||線段trie||trie啟發式合併

題意:一個樹,q次詢問,求xi xor u的子樹的max值 思路:考慮可以直接dfs,對映到數軸上,然後就是裸的可持久化trie了。。時間複雜度nlogn,同理nlognlogn可以線段樹套trie(這個題沒按這個寫。。應該可以?參考51nod1295,第一次寫可持久化trie就是樹套樹水過

BZOJ 3261 淺談可持久化TRIE最大連續異或和

世界真的很大 trie樹貪心求最大異或和大概也就是那麼回事了 但是對於區間的查詢就不是那麼容易的了 考慮主席樹的思想,怎麼得到區間的值域的 這就是可持久化的trie樹 說來容易 指標教做人哪 看題先: description: 給定一個非負

bzoj 1901 ZOJ 2112 Dynamic Rankings [狀陣列主席] [線段平衡]

Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6900 Solved: 2870 Description 給定一個含有n個數的序列a[1],a[2],a[3]……a[

BZOJ 3196 線段平衡

(程式碼無比醜陋) //By SiriusRen #include <cstdio> #include <algorithm> using namespace std; int n,m,L,R,xx,tx,t,root[3000050]

【bzoj4785】[Zjoi2017]狀數組 線段線段

奇怪 原因 tdi function 數字 二進制位 操作 接下來 還需 題目描述 漆黑的晚上,九條可憐躺在床上輾轉反側。難以入眠的她想起了若幹年前她的一次悲慘的OI 比賽經歷。那是一道基礎的樹狀數組題。給出一個長度為 n 的數組 A,初始值都為 0,接下來進行 m 次操

bzoj3196 二逼平衡——線段平衡

online truct str clu turn fin lan modify .com 題目:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 人生中第一棵樹套樹! 寫了一個晚上,成功卡時 9000ms+ 過了!

BZOJ1513:之線段線段實現二維區間修改和最值查詢

name names algo getch oid min 投影 協調 pan 我們經常提及的二維線段樹有兩種寫法,一種是四分樹,一種是樹套樹,寫成四分樹的都是神仙。 樹套樹寫法還是比較好理解的,不過要是讓自己硬套的話可能很不容易套出來的 這裏的二維線段樹,外層線段樹是對方

hdu-4819-線段線段

air 子矩陣 左右 ref print fin std code 進行 http://acm.hdu.edu.cn/showproblem.php?pid=4819 給出一個N*N的矩陣,每次詢問一個m*m的子矩陣裏的floor((maxv+minv)/2)並把中間的

字典Trie)模板 陣列表示 + 連結串列表示

 陣列模擬,缺點是並不知道要開多大,可能會出現陣列開小導致wrong answer。 對應題目:hdu 1251  #include <iostream> #include <cstdio> #include <cstring> #de

BZOJ4317Atm的&BZOJ2051A Problem For Fun&BZOJ2117[2010國家集訓隊]Crash的旅遊計劃——二分答案+動態點分治(點分線段/點分+vector)

題目描述 Atm有一段時間在虐qtree的題目,於是,他滿腦子都是tree,tree,tree…… 於是,一天晚上他夢到自己被關在了一個有根樹中,每條路徑都有邊權,一個神祕的聲音告訴他,每個點到其他的點有一個距離(什麼是距離不用說吧),他需要對於每個點回答:從這個點出發的第k小距離

字典Trie)附例題(統計難題 HDU

一、基礎理論:        字典樹,又稱單詞查詢樹,Trie樹,是一種樹形結構,是一種雜湊樹的變種。典型應用是用於統計,排序和儲存大量的字串(但不僅限於字串),所以經常被搜尋引擎系統用於文字詞頻統計。 二、基本性質: 根節點不包含字元,除根節點之外每個子節點都包含一個

之線段線段(BZOJ3110、洛谷P3332)

前置技能 當然是線段樹啦! 應用及實現 線段樹可以維護一個序列。當需要維護一個矩陣(即二維平面)內的數值,或者有什麼奇怪的區間操作時,就需要用到二維線段樹,也就是線段樹“套上”線段樹。 當維護一個矩陣時,先建一顆“外面的”線段樹來維護一維,對於每個“

AVL,紅黑,B-B+Trie原理和應用

前言:本文章來源於我在知乎上回答的一個問題 AVL樹,紅黑樹,B樹,B+樹,Trie樹都分別應用在哪些現實場景中? 看完後您可能會了解到這些資料結構大致的原理及為什麼用在這些場景,文章

(轉)字典Trie

對於每一個節點,從根遍歷到他的過程就是一個單詞,如果這個節點被標記為紅色,就表示這個單詞存在,否則不存在。那麼,對於一個單詞,我只要順著他從跟走到對應的節點,再看這個節點是否被標記為紅色就可以知道它是否出現過了。把這個節點標記為紅色,就相當於插入了這個單詞。這樣一來我們詢問和插入可以一起完成,所用時間僅僅為單

查詢(二)簡單清晰的BTrie詳解

查詢(二) 散列表 散列表是普通陣列概念的推廣。由於對普通陣列可以直接定址,使得能在O(1)時間內訪問陣列中的任意位置。在散列表中,不是直接把關鍵字作為陣列的下標,而是根據關鍵字計算出相應的下標。 使用雜湊的查詢演算法分為兩步。第一步是用雜湊函式將被查詢的鍵轉化為陣

查詢------BTrie

查詢(二) 散列表 散列表是普通陣列概念的推廣。由於對普通陣列可以直接定址,使得能在O(1)時間內訪問陣列中的任意位置。在散列表中,不是直接把關鍵字作為陣列的下標,而是根據關鍵字計算出相應的下標。 使用雜湊的查詢演算法分為兩步。第一步是用雜湊函式將被查詢的鍵轉化為陣列的一個索引。 我們需要面對兩個或

B、B-、B+、B*、紅黑、 二叉排序trieDouble Array 字典查詢簡介

B  樹 即二叉搜尋樹:      1.所有非葉子結點至多擁有兩個兒子(Left和Right);       2.所有結點儲存一個關鍵字;       3.非葉子結點的左指標指向小於其關鍵字的子樹,右指標指向大於其關鍵字的子樹;       如:       B樹的