樹分治 複習總結

2022-05-31 06:30:07 字數 4689 閱讀 9617

前幾天去填重建計畫的坑的時候無意中發現自己的樹分治一直有乙個地方有點bug,是錯誤的qaq(但是貌似影響不大

於是皇德耀世,趕緊去找了幾道樹分治來練習一下

bug是每次樹分治找重心的時候sum直接用的w陣列,可是對於每一層w陣列要重新計算(然而我並沒有qaq

wc2010 重建計畫

這是乙份bug重重的**,我用了19min寫完,交上去1a

可是我後來發現這份**至少有三處錯誤qaq資料也太弱了吧

貼乙份bug重重的**吧,順便鍛鍊找bug能力?

做法是二分答案之後每條邊-mid,判斷條件是是否存在邊權和》=0的路徑

#include#include#include#include#include#define eps 1e-5

using namespace std;

const int maxn=100010;

const int oo=0x7fffffff/3;

int n,l,r,tmp;

int u,v,b;

int mn,mx;

double ans,l,r;

int h[maxn],cnt=0;

struct edgeg[maxn<<1];

int g,sum;

int f[maxn],w[maxn];

int son[maxn],tot=0;

double fa[maxn];

double dep[maxn],mx_dep[maxn];

int q[maxn];

bool vis[maxn];

bool cmp(const int &a,const int &b)

void cmax(int &a,int b)

void get_g(int u,int fa)cmax(f[u],sum-w[u]);

if(f[g]>f[u])g=u;

}void get_dis(int u,int f,int d,double dis,double k)

while(h<=t&&q[h]0)return true;

}if(tmp>len)len=tmp;

for(int i=1;i<=len;++i)mx_dep[i]=max(mx_dep[i],dep[i]);

}return false;

}void get_ans(int u)

sort(son+1,son+tot+1,cmp);

while(r-l>eps)ans=l;

}void get_div(int u)return;}

int main()g[maxn<<1];

int g,sum;

int f[maxn],w[maxn],b[maxn];

int son[maxn],tot=0;

int fa[maxn],q[maxn];

int dep[maxn],mx_dep[maxn];

bool cmp(const int &x,const int &y)

void cmax(int &a,int b)

void get_g(int u,int fa)cmax(f[u],sum-w[u]);

if(f[g]>f[u])g=u;

}void dfs(int u,int fa)return;

}void get_dis(int u,int f,int d,int dis)

ans=max(ans,dep[j]+mx);

} if(tmp>len)len=tmp;

for(int j=len;j>=0;--j)

} return;

}void get_div(int u)

sort(son+1,son+tot+1,cmp);

get_ans(u);

for(int i=h[u];i;i=g[i].next)return;

}int main()

for(int i=1;icodeforces 190 div1 c

一道構造題目,要求你給樹上每個點賦上a-z任意乙個字母

要求如果有兩個節點的字母相同,則這兩點間的路徑上一定要有乙個節點的字母比這兩個節點的字母大

定義a>b>c……

其實這道題目的impossible是逗你玩的,不可能無解

我的構造方式就是採用樹分治,樹分治的結構最多有logn層,第一層賦值a,第二層賦值b……

不難發現這樣賦值的正確性,因為當每一層的賦值之後每棵子樹要賦值的數都比當前小,所以子樹是獨立的

恰好滿足樹分治的性質

#include#include#include#include#includeusing namespace std;

const int oo=0x7fffffff/3;

const int maxn=100010;

int n,u,v;

int h[maxn],cnt=0;

struct edgeg[maxn<<1];

int g,sum;

int f[maxn],w[maxn];

char ans[maxn];

bool vis[maxn];

void add(int x,int y)

void read(int &num)

void cmax(int &a,int b)

void get_g(int u,int fa)cmax(f[u],sum-w[u]);

if(f[g]>f[u])g=u;

}void dfs(int u,int f)return;

}void get_div(int u,int d)return;

}int main()g[maxn<<1];

int g,sum,tim;

bool vis[maxn];

int f[maxn],w[maxn];

int mx[maxn<<2];

int t[maxn<<2];

void add(int x,int y)

void read(int &num)

void cmax(int &a,int b)

void upd(int o,int l,int r,int p,int v)

else cmax(mx[o],v);

return;

} int mid=(l+r)>>1;

int l=(o<<1),r=(l|1);

if(p<=mid)upd(l,l,mid,p,v);

else upd(r,mid+1,r,p,v);

t[o]=tim;

int a=(t[l]==tim?mx[l]:0);

int b=(t[r]==tim?mx[r]:0);

mx[o]=max(a,b);

}int ask(int o,int l,int r,int x,int y)

void get_g(int u,int fa)cmax(f[u],sum-w[u]);

if(f[g]>f[u])g=u;

}void dfs(int u,int f)return;

}void get_up(int u,int f,int d)return;

}void get_down(int u,int f,int d)return;

}void dfs_down(int u,int f,int d)return;

}void dfs_up(int u,int f,int d)return;

}void get_div(int u)

tim++;

for(int i=h[u];i;i=g[i].next)

for(int i=h[u];i;i=g[i].next)return;

}int main()g[maxn<<1];

int g,tot,sum;

int mx[5000010];

int nxt[5000010][2];

int f[maxn],w[maxn];

void add(int x,int y)

void read(int &num)

void cmax(int &a,int b)

void get_g(int u,int fa)cmax(f[u],sum-w[u]);

if(f[g]>f[u])g=u;

}void dfs(int u,int f)return;

}int newnode()

void insert(int num,int k)return;

}int ask(int num,int k)

for(int i=h[u];i;i=g[i].next)return;

}int main(){

read(n);read(k);

for(int i=1;i<=n;++i)read(black[i]);

for(int i=1;i<=n;++i)read(c[i]);

for(int i=1;i樹分治通常情況下是解決樹上路徑問題

適用範圍很廣,可以用來最優化問題也可以用來計數

也有一部分的樹分治的問題利用的是重心的性質和樹分治logn層的結構

如果遇到樹上路徑相關問題不妨可以用樹分治嘗試一下

樹分治貌似可以相容很多資料結構來維護資訊?

待完成的幾道題目:

兩道樹分治+fft的

還有一道 紫荊花之戀

一些知識點的坑:

回文相關練習

可持久化trie

複習 動態點分治

點分治,動態點分治,等等等各種分治。因為我的智商經常欠費,導致我對於分治這個方面一竅不通。但是動態點分治這個東西我又不是沒有學過,只是過了這麼久我什麼都不會了。所以還是重新理解一下吧。首先,動態點分治需要構建出點分樹,這個很好處理。找重心是o n o n 每次重心分出來的每一棵子樹的大小都不超過o ...

點分治 複習筆記

之前diaoye的一道題是要用點分治寫.但是我省選前臨時學的點分治,當時又只打了幾個板子,中間又沒有寫過有關的題,於是現在就似乎不太會了,剛好昨天又講了,今天就複習一下 引用講課pp t ppt 裡的一段話 點分治,是處理樹上路徑 連通塊的一種常見演算法。這一類問題有時可以通過lca來處理,但是有的...

演算法課複習 分治

hdu 5178 pairs 傳送門 題意 n個數,問有多少對數差值小於k。思路 排個序,開個佇列。每次乙個新的數先把比它小的都從佇列中去了,然後答案加上佇列大小,最後把自己塞進佇列。按順序走一遍行了。ac include include include include include includ...