遙遠的國度(樹鏈剖分,換根)

2022-04-29 22:15:11 字數 2804 閱讀 7224

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的操作,輸出一行代表對應子樹的最小點權值。

輸入樣例#1:複製

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輸出樣例#1:複製12

34對於20%的資料,n<=1000 m<=1000。

對於另外10%的資料,n<=100000,m<=100000,保證修改為單點修改。

對於另外10%的資料,n<=100000,m<=100000,保證樹為一條鏈。

對於另外10%的資料,n<=100000,m<=100000,沒有修改首都的操作。

對於100%的資料,n<=100000,m<=100000,0《所有權值<=2^31。

終於填了樹鏈剖分換根這個坑了。

就是換根的時候的我們要分類討論而不是真的去換根。

有三種情況。

第一種就是詢問的點就是當前根。

那麼直接輸出整棵樹的最小值就可以了。

第二種就是當前根在詢問的點的子樹內。

那麼我們首先可以發現。

假如當前根就是詢問點的直接連邊的兒子的話。

就相當於在詢問點的子樹去掉當前根的子樹求值。

那麼多次換根就等於詢問的點到當前根的路徑上的所有子樹都去掉。

而這些子樹又奇妙的全包括在詢問的點到當前根的路徑上的第乙個節點。只要把這個點求出來並去掉其子樹就可以了。

第三種就是當前根不在詢問的點的子樹內。

那麼它的子樹還是原來的子樹。

#include#include#include#include#includeusing namespace std;

const int n=1000001;

const int inf=(1ll<<31)-1;

struct nodee[n];

int num,head[n],sum[n],lazy[n];

int n,m,root,dep[n],a[n],top[n];

int fa[n],son[n],size[n],pos[n],ch[n];

int f[n][21],tot;

int read()

while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();

return x*w;

}void add(int from,int to)

void build(int root,int left,int right)

int mid=(left+right)>>1;

build(root<<1,left,mid);build(root<<1|1,mid+1,right);

sum[root]=min(sum[root<<1],sum[root<<1|1]);

}void push(int root,int left,int right)

void update(int root,int left,int right,int l,int r,int v)

if(lazy[root])push(root,left,right);

int mid=(left+right)>>1;

if(mid>=l) update(root<<1,left,mid,l,r,v);

if(midr||right=l&&right<=r)return sum[root];

int mid=(left+right)>>1;int ans1=inf,ans2=inf;

if(mid>=l) ans1=query(root<<1,left,mid,l,r);

if(middep[y])swap(x,y);

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

}int cal2(int x,int y)

int find(int x,int y)

int main()}}

return 0;

}

樹鏈剖分 樹剖換根

這是一道模板題。給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...

樹鏈剖分換根

描述 給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙個節點,將...

BZOJ 3083 遙遠的國度 樹鏈剖分

題目大意 給出一顆無根樹,有鏈的修改操作,還有子樹的查詢。除此之外,還有選定這棵樹的乙個點為根。思路 子樹操作,鏈上修改,帶size域的樹鏈剖分就可以搞定。換根肯定不能真的換,出題人要是閒的沒事所有操作都在換根就慘。我們可以畫一張圖模擬下換根。先按照讀入的順序建一顆有根樹,然後觀察當前的根在要詢問的...