1. 程式人生 > >【bzoj3217】ALOEXT 替罪羊樹套Trie樹

【bzoj3217】ALOEXT 替罪羊樹套Trie樹

uil 重新 return 等於 開始 space 無法 last esp

題目描述

taorunz平時最喜歡的東西就是可移動存儲器了……只要看到別人的可移動存儲器,他總是用盡一切辦法把它裏面的東西弄到手。

突然有一天,taorunz來到了一個密室,裏面放著一排可移動存儲器,存儲器裏有非常珍貴的OI資料……不過比較特殊的是,每個存儲器上都寫著一個非負整數。taorunz很高興,要把所有的存儲器都拿走(taorunz的智商高達500,他一旦弄走了這裏的所有存儲器,在不久到來的AHOI和NOI中……你懂的)。不過這時有一個聲音傳來:“你只能拿走這裏的一個存儲器,而且還不能直接拿,你需要指定一段區間[l, r],滿足l<r,然後在第l個和第r個存儲器之間選一個拿走,你能獲得的知識增加量等於區間[l, r]中所有存儲器上寫的整數的次大值與你拿走的這個存儲器上寫的整數作按位異或運算的結果。”

問題是,這裏的可移動存儲器數量太多,而且,它們還在不斷地發生變化,有時候天上會掉下來一個新的存儲器,並插入到這一排存儲器中,有時候某個存儲器會不明原因消失,有時候某個存儲器上寫的整數變化了。taorunz雖然智商很高,但也無法應對如此快的變化,他指定了許多段區間,讓你幫他找出如果在這個區間中拿走存儲器,他能獲得的最多的知識是多少。

輸入

第一行兩個整數N、M,表示一開始的存儲器數和後面發生的事件數。

第二行N個非負整數,表示一開始從左到右每個存儲器上寫的數字。註意,存儲器從0開始編號,也就是最左邊的存儲器是第0個。

接下來M行,每行描述一個事件,有4種可能的事件。

(1)I x y:表示天上掉下來一個寫著數字y的存儲器,並插入到原來的第x個存儲器之前,如果x等於原來存儲器的個數,則插入到末尾;

(2)D x:表示第x個存儲器消失;

(3)C x y:表示第x個存儲器上寫的數字變為y;

(4)F l r:表示taorunz指定區間[l, r],讓你告訴他最多能獲得多少知識。

註意,本題強制在線,也就是事件中出現的所有數字都進行了加密,數字s表示的真實值是

對於I、D、C事件中的x及F事件中的l、r:(s+last_ans) mod n0;

對於I、C事件中的y:(s+last_ans) mod 1048576。

其中n0為目前存儲器個數,last_ans為上一個F事件的結果,如果前面尚未發生F事件,則last_ans=0。

輸出

對於每個F事件,輸出結果。

樣例輸入

5 10
2 6 3 8 7
F 1 4
I 2 1048565
I 0 1048566
D 3
F 3 0
I 3 1048569
D 5
C 1 1048570
F 1 2
F 2 1

樣例輸出

15
7
4
7


題解

替罪羊樹套Trie樹

題目要求支持定點插入,所以需要使用平衡樹;而又要求出最大異或值,顯然還要使用Trie樹貪心。

考慮把它們套起來,那麽平衡樹需要放在外層,所以選擇替罪羊樹。

於是本題就與 bzoj3065 差不多,對替罪羊樹的每一個節點,維護它本身和它子樹所有權值的01Trie樹以及次大值,查詢時直接提取所有區間然後按位貪心求最大異或即可。

但是本題與那道題不同的是,本題有刪除操作,所以替罪羊樹還需要支持刪除。

具體方法是:和普通BST是一樣的刪除方法,如果一個節點存在某子樹為空則把這棵子樹提到該節點的位置,否則尋找這個點的後繼節點(右子樹中第一個節點),用這個節點替換原來的節點。由於刪除帶來的子樹大小變化使得勢能分析帶來的結果不正確,因此刪除時不能重構樹,否則時間復雜度會出錯。解決方法是:對於每個點維護一個maxsize,即子樹大小的歷史最大值。如果這個歷史最大值超過父親節點的歷史最大值的某比例便重構,重構的時候把歷史最大值也重新賦值。

時間復雜度應該是$O(20n\log^2n)=O(能過)$。

本題同樣需要內存回收,而且數組要開到$2.5*10^7$左右才能夠通過。

為了方便內存回收使用了遞歸版的Trie樹插入所以代碼跑得慢一些= =

另外解釋下代碼中pushup中的if:由於我刪除的姿勢問題,使得在某些特殊情況下會pushup到0節點,導致它的size變為1,然後就全局錯誤。因此防止這種情況加了判斷(於是代碼就更慢了= =)

#include <queue>
#include <cstdio>
#include <utility>
#include <algorithm>
using namespace std;
typedef pair<int , int> pr;
struct scg
{
	int ls , rs , si , ms , w , wr , tr;
	pr mx;
}a[200010];
struct trie
{
	int c[2] , si;
}b[25000010];
queue<int> q;
int n , root , pos[200010] , tot , qr[1000] , qt;
char str[5];
void update(int v , int d , int a , int &x)
{
	if(!x) x = q.front() , q.pop();
	b[x].si += a;
	bool t = v & (1 << d);
	if(~d) update(v , d - 1 , a , b[x].c[t]);
	if(!b[x].si) q.push(x) , x = 0;
}
void del(int &x)
{
	if(!x) return;
	del(b[x].c[0]) , del(b[x].c[1]);
	b[x].si = 0 , q.push(x) , x = 0;
}
int query(int v , int d)
{
	if(d == -1) return 0;
	int i;
	bool t = v & (1 << d);
	for(i = 1 ; i <= qt ; i ++ )
		if(b[qr[i]].c[t ^ 1])
			break;
	if(i <= qt)
	{
		for(i = 1 ; i <= qt ; i ++ ) qr[i] = b[qr[i]].c[t ^ 1];
		return query(v , d - 1) + (1 << d);
	}
	else
	{
		for(i = 1 ; i <= qt ; i ++ ) qr[i] = b[qr[i]].c[t];
		return query(v , d - 1);
	}
}
inline pr getmx(pr a , pr b)
{
	if(a.first > b.first) return pr(a.first , max(b.first , max(a.second , b.second)));
	else return pr(b.first , max(a.first , max(a.second , b.second)));
}
inline void pushup(int x)
{
	if(!x) return;
	a[x].si = a[a[x].ls].si + a[a[x].rs].si + 1 , a[x].ms = max(a[x].ms , a[x].si);
	a[x].mx = getmx(pr(a[x].w , -1 << 30) , getmx(a[a[x].ls].mx , a[a[x].rs].mx));
}
int build(int l , int r)
{
	if(l > r) return 0;
	int mid = (l + r) >> 1 , i;
	for(i = l ; i <= r ; i ++ ) update(a[pos[i]].w , 20 , 1 , a[pos[mid]].tr);
	a[pos[mid]].ls = build(l , mid - 1) , a[pos[mid]].rs = build(mid + 1 , r);
	pushup(pos[mid]);
	return pos[mid];
}
void dfs(int &x)
{
	if(!x) return;
	dfs(a[x].ls) , pos[++tot] = x , dfs(a[x].rs);
	a[x].si = a[x].ms = 0 , del(a[x].tr) , x = 0;
}
void insert(int p , int v , int &x , bool flag)
{
	if(!x)
	{
		x = ++n , a[x].w = v , update(v , 20 , 1 , a[x].wr) , update(v , 20 , 1 , a[x].tr) , pushup(x);
		return;
	}
	bool tag;
	update(v , 20 , 1 , a[x].tr);
	if(p <= a[a[x].ls].si) tag = (max(a[a[x].ls].ms , a[a[x].ls].si + 1) * 4 > max(a[x].ms , a[x].si + 1) * 3) , insert(p , v , a[x].ls , tag || flag);
	else tag = (max(a[a[x].rs].ms , a[a[x].rs].si + 1) * 4 > max(a[x].ms , a[x].si + 1) * 3) , insert(p - a[a[x].ls].si - 1 , v , a[x].rs , tag || flag);
	pushup(x);
	if(tag && !flag) tot = 0 , dfs(x) , x = build(1 , tot);
}
int find(int p , int x)
{
	if(p <= a[a[x].ls].si) return find(p , a[x].ls);
	else if(p > a[a[x].ls].si + 1) return find(p - a[a[x].ls].si - 1 , a[x].rs);
	else return a[x].w;
}
void erase(int p , int v , int &x)
{
	update(v , 20 , -1 , a[x].tr);
	if(p <= a[a[x].ls].si) erase(p , v , a[x].ls);
	else if(p > a[a[x].ls].si + 1) erase(p - a[a[x].ls].si - 1 , v , a[x].rs);
	else
	{
		if(!a[x].ls || !a[x].rs) x = a[x].ls + a[x].rs;
		else
		{
			int t = a[x].rs;
			while(a[t].ls) t = a[t].ls;
			erase(1 , a[t].w , a[x].rs);
			a[t].ls = a[x].ls , a[t].rs = a[x].rs , a[t].tr = a[x].tr , x = t;
		}
	}
	pushup(x);
}
void modify(int p , int v1 , int v2 , int x)
{
	update(v1 , 20 , -1 , a[x].tr) , update(v2 , 20 , 1 , a[x].tr);
	if(p <= a[a[x].ls].si) modify(p , v1 , v2 , a[x].ls);
	else if(p > a[a[x].ls].si + 1) modify(p - a[a[x].ls].si - 1 , v1 , v2 , a[x].rs);
	else del(a[x].wr) , update(v2 , 20 , 1 , a[x].wr) , a[x].w = v2;
	pushup(x);
}
pr solve(int b , int e , int x)
{
	if(b <= 1 && e >= a[x].si) return a[x].mx;
	pr ans = pr(-1 << 30 , -1 << 30);
	if(b <= a[a[x].ls].si + 1 && e >= a[a[x].ls].si + 1) ans = getmx(ans , pr(a[x].w , -1 << 30));
	if(b <= a[a[x].ls].si) ans = getmx(ans , solve(b , e , a[x].ls));
	if(e > a[a[x].ls].si + 1) ans = getmx(ans , solve(b - a[a[x].ls].si - 1 , e - a[a[x].ls].si - 1 , a[x].rs));
	return ans;
}
void split(int b , int e , int x)
{
	if(!x) return;
	if(b <= 1 && e >= a[x].si)
	{
		qr[++qt] = a[x].tr;
		return;
	}
	if(b <= a[a[x].ls].si + 1 && e >= a[a[x].ls].si + 1) qr[++qt] = a[x].wr;
	if(b <= a[a[x].ls].si) split(b , e , a[x].ls);
	if(e > a[a[x].ls].si + 1) split(b - a[a[x].ls].si - 1 , e - a[a[x].ls].si - 1 , a[x].rs);
}
int main()
{
	int m , i , last = 0 , x , y;
	for(i = 1 ; i <= 25000000 ; i ++ ) q.push(i);
	scanf("%d%d" , &n , &m);
	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i].w) , update(a[i].w , 20 , 1 , a[i].wr) , pos[i] = i;
	root = build(1 , n);
	while(m -- )
	{
		scanf("%s" , str);
		switch(str[0])
		{
			case ‘I‘: scanf("%d%d" , &x , &y) , x = (x + last) % a[root].si + 1 , y = (y + last) % 1048576 , insert(x - 1 , y , root , 0); break;
			case ‘D‘: scanf("%d" , &x) , x = (x + last) % a[root].si + 1 , erase(x , find(x , root) , root); break;
			case ‘C‘: scanf("%d%d" , &x , &y) , x = (x + last) % a[root].si + 1 , y = (y + last) % 1048576 , modify(x , find(x , root) , y , root); break;
			default: scanf("%d%d" , &x , &y) , x = (x + last) % a[root].si + 1 , y = (y + last) % a[root].si + 1 , qt = 0 , split(x , y , root) , printf("%d\n" , last = query(solve(x , y , root).second , 20));
		}
	}
	return 0;
}

【bzoj3217】ALOEXT 替罪羊樹套Trie樹