bzoj3083 遙遠的國度 樹鏈剖分 線段樹

2022-05-20 11:02:28 字數 2570 閱讀 7277

題目描述

描述zcwwzdjn在追殺十分sb的zhx,而zhx逃入了乙個遙遠的國度。當zcwwzdjn準備進入遙遠的國度繼續追殺時,守護神rapid阻攔了zcwwzdjn的去路,他需要zcwwzdjn完成任務後才能進入遙遠的國度繼續追殺。

問題是這樣的:遙遠的國度有n個城市,這些城市之間由一些路連線且這些城市構成了一顆樹。這個國度有乙個首都,我們可以把這個首都看做整棵樹的根,但遙遠的國度比較奇怪,首都是隨時有可能變為另外乙個城市的。遙遠的國度的每個城市有乙個防禦值,有些時候rapid會使得某兩個城市之間的路徑上的所有城市的防禦值都變為某個值。rapid想知道在某個時候,如果把首都看做整棵樹的根的話,那麼以某個城市為根的子樹的所有城市的防禦值最小是多少。由於rapid無法解決這個問題,所以他攔住了zcwwzdjn希望他能幫忙。但zcwwzdjn還要追殺sb的zhx,所以這個重大的問題就被轉交到了你的手上。

輸入第1行兩個整數n m,代表城市個數和運算元。

第2行至第n行,每行兩個整數 u v,代表城市u和城市v之間有一條路。

第n+1行,有n個整數,代表所有點的初始防禦值。

第n+2行乙個整數 id,代表初始的首都為id。

第n+3行至第n+m+2行,首先有乙個整數opt,如果opt=1,接下來有乙個整數id,代表把首都修改為id;如果opt=2,接下來有三個整數p1 p2 v,代表將p1 p2路徑上的所有城市的防禦值修改為v;如果opt=3,接下來有乙個整數 id,代表詢問以城市id為根的子樹中的最小防禦值。

輸出對於每個opt=3的操作,輸出一行代表對應子樹的最小點權值。

樣例輸入

3 71 2

1 31 2 3

13 1

2 1 1 6

3 12 2 2 5

3 12 3 3 4

3 1樣例輸出12

34題解樹鏈剖分+線段樹

後兩個操作是樹剖的基本操作,而換根操作是我們需要重點解決的。

首先換根不能真的換,也不能使用lct(因為不能維護子樹),我們需要思考換根之後子樹的變化。

設所求為x的子樹,當前的根為root,那麼分3種情況討論:

1.root=x,那麼子樹直接就是整棵樹。

2.root在原來x的父樹中,即root不在原來x的子樹中,那麼當前x的子樹就是原來x的子樹,因為遍歷序是相同的。

所以樹剖之後記錄子樹範圍,如果是第三種情況再求乙個rs即可。

如何求rs?其實和樹剖求lca差不多。

考慮root是怎麼跳到x的,最後一步只有兩種情況:從重鏈跳到x、從輕鏈跳到x。從重鏈的情況,rs就是x的重兒子,在dfs時順便記錄一下就好了;從輕鏈的情況,最後一步一定是從x的兒子跳過來的,所以跳過來前的那個節點就是rs。

說了這麼多其實**真心簡單。

最後:本題有毒。1280mb的空間限制各種誤導開nlogn大陣列qaq,權值「<=2^31」爆int,需要unsigned int qaq

#include #include #define n 100010

#define lson l , mid , x << 1

#define rson mid + 1 , r , x << 1 | 1

using namespace std;

int head[n] , to[n << 1] , next[n << 1] , cnt , n;

int fa[n] , deep[n] , si[n] , bl[n] , pos[n] , tot , son[n] , last[n];

unsigned v[n] , minn[n << 2] , tag[n << 2];

void add(int x , int y)

void dfs1(int x)

void dfs2(int x , int c)

last[x] = tot;

}void pushup(int x)

void pushdown(int x)

void build(int l , int r , int x)

int mid = (l + r) >> 1;

build(lson) , build(rson) , pushup(x);

}void update(int b , int e , unsigned a , int l , int r , int x)

pushdown(x);

int mid = (l + r) >> 1;

if(b <= mid) update(b , e , a , lson);

if(e > mid) update(b , e , a , rson);

pushup(x);

}unsigned query(int b , int e , int l , int r , int x)

int find(int x , int s)

return son[x];

}void modify(int x , int y , unsigned a)

if(deep[x] > deep[y]) swap(x , y);

update(pos[x] , pos[y] , a , 1 , n , 1);

}int main()

return 0;

}

bzoj3083 遙遠的國度

題意 給定一棵樹,支援換根,路徑權值覆蓋,求子樹最小。思路 求子樹?上樹鏈剖分,但是換根怎麼辦?我們只能通過原有資訊推出換根後的答案。換根不影響路徑修改,所以只要考慮子樹最小值的維護。這裡要分3種情況討論 1 如果詢問點是當前根,直接返回整棵樹的最小值。2 如果在原樹中,當前根不在 x的子樹中,直接...

bzoj3083 遙遠的國度

time limit 10 sec memory limit 1280 mb submit 1733 solved 429 submit status discuss description 描述 zcwwzdjn在追殺十分sb的zhx,而zhx逃入了乙個遙遠的國度。當zcwwzdjn準備進入遙遠的...

bzoj3083 遙遠的國度

time limit 10 sec memory limit 1280 mb submit 1960 solved 484 submit status discuss 描述zcwwzdjn在追殺十分sb的zhx,而zhx逃入了乙個遙遠的國度。當zcwwzdjn準備進入遙遠的國度繼續追殺時,守護神ra...