1. 程式人生 > >【bzoj2770】YY的Treap 權值線段樹

【bzoj2770】YY的Treap 權值線段樹

urn 復雜度 efi ras char 小結 second treap 子節點

題目描述

誌向遠大的YY小朋友在學完快速排序之後決定學習平衡樹,左思右想再加上SY的教唆,YY決定學習Treap。友愛教教父SY如砍瓜切菜般教會了YY小朋友Treap(一種平衡樹,通過對每個節點隨機分配一個priority,同時保證這棵平衡樹關於priority是一個小根堆以保證效率)。這時候不怎麽友愛的510跑了出來,他問了YY小朋友一個極不和諧的問題:怎麽求Treap中兩個點之間的路徑長度。YY秒了之後決定把這個問題交給你來做,但只要求出樹中兩點的LCA。

輸入

第一行兩個整數n,m

第二行n個整數表示每個元素的key

第三行n個整數表示每個元素的priority

接下m行,每行一條命令

I A B,插入一個元素,key為A, priority為B

D A,刪除一個元素,key為A

Q A B,詢問key分別為A和B的LCA的key

輸出

對於每個Q輸出一個整數。

樣例輸入

2 1
1 2
4 5
Q 1 2

樣例輸出

1


題解

權值線段樹

一個小結論:不妨設$a\le b$,則Treap中權值為$a$、$b$兩點的LCA為權值在$[a,b]$之間,優先級最小的點。

證明:

1.LCA的權值在$[a,b]$之間:考慮從$a$、$b$找到LCA的最後一步:一定是$a$在LCA的非右子樹,$b$在LCA的非左子樹。否則$a$、$b$在同子樹內則LCA可以為更優的該兒子節點。

2.權值在$[a,b]$之間的節點一定都在LCA的子樹內:如果不在LCA的子樹內,那麽節點如果在LCA右側則一定大於$b$,或在LCA左側則一定小於$a$。

3.LCA的子樹中所有節點的優先級都小於等於LCA:證明顯然。

4.LCA一定在LCA的子樹內:證明顯然。

因此由1、2、3、4得證。

於是只需要對每個數的key維護權值線段樹,維護權值在某區間內的數的優先級最小值及其位置。查詢時直接區間查詢即可。

為了避免一些細節問題(比如兩個int加起來爆int之類的),代碼中使用了離線離散化。

時間復雜度$O(n\log n)$。

#include <cstdio>
#include <utility>
#include <algorithm>
#define N 100010
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
#define id(x) lower_bound(v + 1 , v + tot + 1 , x) - v
#define inf 0x7fffffff
using namespace std;
typedef pair<int , int> pr;
int key[N] , pri[N] , opt[N * 3] , qx[N * 3] , qy[N * 3] , v[N << 2] , tot;
pr mn[N << 4];
char str[5];
void build(int l , int r , int x)
{
	mn[x] = pr(inf , inf);
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(lson) , build(rson);
}
void insert(int p , int v , int l , int r , int x)
{
	if(l == r)
	{
		mn[x] = pr(v , p);
		return;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) insert(p , v , lson);
	else insert(p , v , rson);
	mn[x] = min(mn[x << 1] , mn[x << 1 | 1]);
}
void erase(int p , int l , int r , int x)
{
	if(l == r)
	{
		mn[x] = pr(inf , inf);
		return;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) erase(p , lson);
	else erase(p , rson);
	mn[x] = min(mn[x << 1] , mn[x << 1 | 1]);
}
pr query(int b , int e , int l , int r , int x)
{
	if(b <= l && r <= e) return mn[x];
	int mid = (l + r) >> 1;
	pr ans(inf , inf);
	if(b <= mid) ans = min(ans , query(b , e , lson));
	if(e > mid) ans = min(ans , query(b , e , rson));
	return ans;
}
int main()
{
	int n , m , i;
	scanf("%d%d" , &n , &m);
	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &key[i]) , v[++tot] = key[i];
	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &pri[i]);
	for(i = 1 ; i <= m ; i ++ )
	{
		scanf("%s%d" , str , &qx[i]);
		if(str[0] == ‘I‘) opt[i] = 1 , scanf("%d" , &qy[i]) , v[++tot] = qx[i];
		else if(str[0] == ‘D‘) opt[i] = 2;
		else opt[i] = 3 , scanf("%d" , &qy[i]);
	}
	sort(v + 1 , v + tot + 1);
	build(1 , tot , 1);
	for(i = 1 ; i <= n ; i ++ ) insert(id(key[i]) , pri[i] , 1 , tot , 1);
	for(i = 1 ; i <= m ; i ++ )
	{
		if(opt[i] == 1) insert(id(qx[i]) , qy[i] , 1 , tot , 1);
		else if(opt[i] == 2) erase(id(qx[i]) , 1 , tot , 1);
		else if(qx[i] < qy[i]) printf("%d\n" , v[query(id(qx[i]) , id(qy[i]) , 1 , tot , 1).second]);
		else printf("%d\n" , v[query(id(qy[i]) , id(qx[i]) , 1 , tot , 1).second]);
	}
	return 0;
}

【bzoj2770】YY的Treap 權值線段樹