乙個有根樹,以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 的所有相鄰邊中時間...