目錄
例題2
樹的重心也叫樹的質心。對於一棵樹n個節點的無根樹,找到乙個點,使得把樹變成以該點為根的有根樹時,最大子樹的結點數最小。換句話說,刪除這個點後最大連通塊(一定是樹)的結點數最小。如圖:
找重心可以一遍dfs得出。
洛谷p4149 [ioi2011]race
求樹中長度為k,且經過邊數最少的路徑。\((k \leq 10^6)\)
思路:開乙個陣列,記錄長度為\(i\)的路徑的最少邊數,遍歷到長度為\(i\)的路徑時,查詢長度為\(k-i\)的路徑。
清陣列不能暴力,要開乙個棧,記錄所有修改,再針對這些修改清空。
#include int fr[200010],ne[400010];
int v[400010],w[400010],bs=0;
void addb(int a,int b,int c)
int mi,wz,dx[200010];
bool bk[200010]=;
void getroot(int u,int f,int sl)
if(sl-dx[u]>ma)
ma=sl-dx[u];
if(ma[bjoi2017]樹的難題
將每個點的子樹按顏色排序,並使用線段樹維護最大權值。
時間複雜度\(o(n\log ^2n)\)
\(n\leq2*10^5\),時限2秒,會卡常。
考慮如下常數優化:
由於邊權為1,所以計算每棵子樹時,最大的長度就是這個節點到葉子結點的最長鏈長度(設為m)。
在計算時,將線段樹重建,範圍為0~m。
這樣,查詢時的複雜度就會小一些,變成\(o(\log m)\)。
並且無需在最後清空線段樹,直接重建時清空就行了。
這樣就能過了。
#include #include int fr[200010],ne[400010],n;
int v[400010],w[400010],bs=0;
int c[200010];
int inf=999999999;
#define re register
inline int max(int a,int b)
void addb(int a,int b,int c)
struct sxds
int m=(l+r)>>1;
jianshu(i<<1,l,m);
jianshu((i<<1)|1,m,r);
}void pushup(int i)
void xiugai(re int i,re int l,re int r,re int j,re int x)
re int m=(l+r)>>1;
if(j>1;
re int t1=chaxun(i<<1,l,m,l,r),t2=chaxun((i<<1)|1,m,r,l,r);
if(t2>t1)
t1=t2;
return t1;
}};sxds xt,bt;
bool bk[200010];
int dfs1(re int u,re int f)
return rt;
}int mi=inf,wz;
int dfs2(re int u,re int f,re int si)
}if(si-rt>zd)
zd=si-rt;
if(zdz-((spx*)b)->z;
}int zc;
void dfs5(int u,int f,int sd)
}void dfs3(re int u,re int f,re int co,re int la,re int he,re int jl)
}void solve(int u)
}qsort(px,sl,sizeof(spx),cmp);
tp=0;
re int la,lx=0;
zc=-inf;
dfs5(u,-1,0);
zc+=1;
xt.jianshu(1,0,zc);
bt.jianshu(1,0,zc);
bt.xiugai(1,0,zc,0,0);
for(re int i=0;i0&&px[i].z!=px[i-1].z)
lx=tp;
}dfs3(px[i].u,u,px[i].z,px[i].z,0,1);
for(int j=la;jxt.sz[cd[st[j]]])
xt.xiugai(1,0,zc,cd[st[j]],qz[st[j]]);}}
}void dfs4(int u)
}}int main()
{ int m;
scanf("%d%d%d%d",&n,&m,&cl,&cr);
for(int i=1;i<=n;i++)
fr[i]=-1;
for(int i=1;i<=m;i++)
scanf("%d",&c[i]);
for(int i=0;i
動態點分治總結
標籤 動態點分治 其實也沒有做很多道題,但是還是總結一波吧.要知道動態點分治,首先得知道點分治.點分治就是對於乙個聯通塊,求出這個聯通塊的重心,然後把這個聯通塊分為很多個聯通塊,這些聯通塊都為這個重心的子樹,那麼求出這些子樹對於重心的貢獻,然後遞迴地做下去,由於重心的每一棵子樹大小都小於聯通塊的一半...
點分治 動態點分治
實在拖得太久了。先扔掉資料 分治的核心是盡量把乙個整體分成接近的兩個部分,這樣遞迴處理可以讓複雜度從n 變成nlogn。兩個問題,如何區分和如何算答案。對於第乙個問題,重心,然後就是找重心的方法,兩個dfs,對於第二個問題,對於每個重心算當前塊中每個點到重心的答案,然後由重心分開的塊要把多餘的資訊去...
點分治與動態點分治
點分治一般是用於解決樹上路徑問題。樹的重心 把重心這個點割掉後,使所形成的最大的聯通塊大小最小的點。可以證明重心子樹的大小最大不會超過 n over 2 重心可以通過 dfs 一遍求出。maxsiz x 表示割掉點x後所形成的的最大的聯通塊的大小 void dfs int x,int fa max ...