DSU 樹上的文藝的暴力

2021-08-28 07:26:45 字數 1123 閱讀 2023

乙個有根樹,以1為根。多次詢問,每次詢問u的k級後代有多少個。

第一行兩個數n,m表示樹的大小和詢問個數

之後n-1行每行兩個數a b表示a和b之間有一條邊

之後m行每行兩個數u,k表示乙個詢問,問u的k級後代有多少個

輸出m行,代表每個詢問的答案

7 12 1

3 14 2

5 26 3

7 31 2

n<=300000, m<=300000

首先想n^2暴力,對於每一次詢問,我們將會遍歷一遍x的子樹統計答案,之後再刪除答案繼續下乙個問題。

然後我們發現,這樣做乙個節點會被統計、刪除多次,浪費資源。這樣我們試著能否不刪除只統計?答案是不可能完全做到。

是的,我們試著對整棵樹進行詢問,由於是自底向上的,乙個節點完全可以繼承它子樹的所有資訊。但是這樣的話,在統計其他子樹時會與其衝突,因此我們選擇的那個繼承資訊點要最後做。

那麼如何選點呢?選重兒子。那麼重兒子只會插入不會刪除,由於乙個點u到根有不超過logn條輕鏈,因此u會被插入刪除logn次,總時間複雜度nlogn。

ps:這些所謂的啟發式合併,只不過是在暴力的基礎上優化了一下操作順序,從n->logn,真是優秀~ ~

#includeusing namespace std;

const int maxn=300005;

struct edge

}e;#define to e.to[p]

struct query;vectorvec[maxn];

int dep[maxn],siz[maxn],son[maxn];

int sum[maxn],ans[maxn];

void getson(int x,int fa,int dep)

}void update(int x,int fa,int v)

void dsu(int x,int fa)

int main()

getson(1,0,0);

for(int i=1;i<=m;++i));

} dsu(1,0);

for(int i=1;i<=m;++i)printf("%d\n",ans[i]);

return 0;

}

樹上的回文

羅馬種了一棵樹,樹上有n個點。每個點有乙個小寫英文本母。1號點是樹的根,剩下的n 1個點都有乙個父親。點和父親之間通過乙個邊相連。第i個點的父親是pi,且pi乙個點的深度是從根到當前點的路徑上經過的點數。根的深度是1。u在v的子樹中,當且僅當u往根方向走可以到達v。特別的,v也是在v的子樹中。羅馬給...

樹上差分的整理(點的樹上差分和邊的樹上差分)

點的樹上差分 若經過 u 到 v 的所有點,tmp u tmp v tmp lca u,v tmp parent lca u,v 0 例題 include using namespace std struct ss ss data 600010 int n,q int a 300010 head 6...

CSP S 2019 樹上的數(樹上推理)

過了這麼久看看自己要多久才能切這題,發現還是想歪了一次。先考慮暴力的做法。還是貪心的逐位確定,逐位確定判有沒有解,相當於下面的問題 樹上有一些路徑,一條路徑表示要把 x 的數字換到 y 去,問有沒有解。對於一條路徑 p 1 p 2 p m 限制如下 1.p 1 p 2 是 p 1 的所有相鄰邊中時間...