BZOJ3083 遙遠的國度 樹剖

2022-02-27 18:32:16 字數 2932 閱讀 1658

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

3 12 1 1 6

3 12 2 2 5

3 12 3 3 4

3 1對於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。

樹剖,較為休閒

主要是換根問題,只影響詢問結果

如果根與詢問節點u的lca不為u,說明根在原樹u的子樹外,這樣子換根後u的子樹不變

如果lca為u,那麼換根後只有根所在原樹u的子樹不在換根後u的子樹內

#include#include#include#include#include#define ll long long int

#define rep(i,n) for (int i = 1; i <= (n); i++)

#define redge(u) for (int k = h[u],to; k; k = ed[k].nxt)

#define ls (u << 1)

#define rs (u << 1 | 1)

using namespace std;

const int maxn = 100005,maxm = 100005,inf = 1000000000;

inline int read()

while (c >= 48 && c <= 57)

return out * flag;

}int h[maxn],ne = 2;

struct edgeed[2 * maxn];

inline void build(int u,int v); h[u] = ne++;

ed[ne] = (edge); h[v] = ne++;

}int n,m,val[maxn],capi;

int siz[maxn],dep[maxn],fa[maxn][18],top[maxn],son[maxn],id[maxn],hash[maxn],cnt;

void dfs1(int u)

}void dfs2(int u,int flag)

int mn[4 * maxn],tag[4 * maxn];

void pd(int u)

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

int mid = l + r >> 1;

build(ls,l,mid);

build(rs,mid + 1,r);

mn[u] = min(mn[ls],mn[rs]);

}void modify(int u,int l,int r,int l,int r,int v)

pd(u);

int mid = l + r >> 1;

if (mid >= l) modify(ls,l,mid,l,r,v);

if (mid < r) modify(rs,mid + 1,r,l,r,v);

mn[u] = min(mn[ls],mn[rs]);

}int query(int u,int l,int r,int l,int r)

int lca(int u,int v)

for (int i = 17; i >= 0; i--)

if (fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];

return u;

}void solve1(int u,int v,int x)

if (dep[u] > dep[v]) swap(u,v);

modify(1,1,n,id[u],id[v],x);

}void solve2(int u)

int lca = lca(u,capi);

if (fa[lca][0] != u) printf("%d\n",query(1,1,n,id[u],id[u] + siz[u] - 1));

else

}int main()else solve2(read());

} return 0;

}

BZOJ 3083 遙遠的國度 樹剖

一開始看到有換根操作可是把我嚇了一跳,我還以為要上top tree呢,結果一開題解。心塞 如果除去換根操作的話就是一道裸的樹鏈剖分了,沒什麼難度,但是加上換根操作以後,別怕,其實聯絡查詢的點和現在的根節點只有4種可能 分3種操作 這裡的討論均基於以1為根節點的有根樹討論 1.x rt 直接查詢整個樹...

BZOJ 3083 遙遠的國度 樹剖 線段樹

傳送門 前兩個操作都比較基礎。對於第三個操作分類討論一下,首先如果當前根不是要操作點的子樹,那麼就無影響,直接查詢操作點的子樹即可。第二種是當前根是操作點的子樹,那就找到當前根到操作點這條鏈的頂端 也就是操作點的兒子,這個兒子為當前根的祖先 然後將這塊連續的 dfs 序挖掉,查詢兩邊就行了。找這個點...

BZOJ 3083 遙遠的國度 樹鏈剖分

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