點分治總結

2021-09-27 09:08:03 字數 2635 閱讀 6981

目錄

例題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 ...