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域的樹鏈剖分就可以搞定。換根肯定不能真的換,出題人要是閒的沒事所有操作都在換根就慘。我們可以畫一張圖模擬下換根。先按照讀入的順序建一顆有根樹,然後觀察當前的根在要詢問的...