一開始看到有換根操作可是把我嚇了一跳,我還以為要上top-tree呢,結果一開題解。。。。。。。。。。心塞
如果除去換根操作的話就是一道裸的樹鏈剖分了,沒什麼難度,但是加上換根操作以後,別怕,其實聯絡查詢的點和現在的根節點只有4種可能(分3種操作),這裡的討論均基於以1為根節點的有根樹討論
1.x==rt 直接查詢整個樹
2.rt是x的祖先 直接查詢x為根的子樹即可
3.x是rt的祖先 令u為x到rt這一段路徑離rt最近的節點,答案就是整個樹除了u這個子樹的最小點權
4.x和rt不是祖孫關係 直接查詢x為根的子樹即可
然後返現2,4可以一起討論,求一下lca就好判斷了。。。。ok
#include#include#include#define maxn 100021
#define ls u<<1,l,mid
#define rs u<<1|1,mid+1,r
using namespace std;
int nu[maxn],f[maxn],p[maxn][20],size[maxn],n,m,son[maxn],head[maxn],rt;
int h[maxn],tot,etot=1,f[maxn],top[maxn],in[maxn],out[maxn],cnt,val[maxn];
struct edgee[maxn*2];
void adde(int a,int b)
/****************剖分啊*********************/
void dfs1(int u,int fa)
}void dfs2(int u,int fa,int tt)
out[u]=cnt;
}/****************線段樹************************/
int min[maxn*4],lz[maxn*4];
inline void push_down(int u)
inline void push_up(int u)
void build(int u,int l,int r)
int mid=l+r>>1;
build(ls),build(rs);
push_up(u);
}void update(int u,int l,int r,int x,int y,int add)int mid=l+r>>1;
push_down(u);
if(x>mid)update(rs,x,y,add);
else if(y<=mid)update(ls,x,y,add);
else update(ls,x,mid,add),update(rs,mid+1,y,add);
push_up(u);
}int query(int u,int l,int r,int x,int y)
/****************************剖分操作******************************/
void change(int a,int b,int c)
if(h[a]>h[b])swap(a,b);
update(1,1,n,nu[a],nu[b],c);
}int lca(int a,int b)return h[a]>h[b] ? b : a;
}int main(){
scanf("%d%d",&n,&m);
for(int a,b,i=1;i=0;i--)if(h[p[b][i]]>h[a])b=p[b][i];
int ans=query(1,1,n,1,in[b]-1);
if(out[b]
BZOJ3083 遙遠的國度 樹剖
zcwwzdjn在追殺十分sb的zhx,而zhx逃入了乙個遙遠的國度。當zcwwzdjn準備進入遙遠的國度繼續追殺時,守護神rapid阻攔了zcwwzdjn的去路,他需要zcwwzdjn完成任務後才能進入遙遠的國度繼續追殺。問題是這樣的 遙遠的國度有n個城市,這些城市之間由一些路連線且這些城市構成了...
BZOJ 3083 遙遠的國度 樹剖 線段樹
傳送門 前兩個操作都比較基礎。對於第三個操作分類討論一下,首先如果當前根不是要操作點的子樹,那麼就無影響,直接查詢操作點的子樹即可。第二種是當前根是操作點的子樹,那就找到當前根到操作點這條鏈的頂端 也就是操作點的兒子,這個兒子為當前根的祖先 然後將這塊連續的 dfs 序挖掉,查詢兩邊就行了。找這個點...
BZOJ 3083 遙遠的國度 樹鏈剖分
題目大意 給出一顆無根樹,有鏈的修改操作,還有子樹的查詢。除此之外,還有選定這棵樹的乙個點為根。思路 子樹操作,鏈上修改,帶size域的樹鏈剖分就可以搞定。換根肯定不能真的換,出題人要是閒的沒事所有操作都在換根就慘。我們可以畫一張圖模擬下換根。先按照讀入的順序建一顆有根樹,然後觀察當前的根在要詢問的...