設 T 爲一棵有根樹,咱們作以下的定義:c++
• 設 a 和 b 爲 T 中的兩個不一樣節點。若是 a 是 b 的祖先,那麼稱「a 比 b 不知道高明到哪裏去了」。測試
• 設 a 和 b 爲 T 中的兩個不一樣節點。若是 a 與 b 在樹上的距離不超過某個給定常數 x,那麼稱「a 與 b 談笑風生」。spa
給定一棵 n 個節點的有根樹 T,節點的編號爲 1 ∼ n,根節點爲 1 號節點。你須要回答 q 個詢問,詢問給定兩個整數 p 和 k,問有多少個有序三元組 (a; b; c) 知足:code
a、 b 和 c 爲 T 中三個不一樣的點,且 a 爲 p 號節點;ip
a 和 b 都比 c 不知道高明到哪裏去了;get
a 和 b 談笑風生。這裏談笑風生中的常數爲給定的 k。it
輸入格式:io
輸入文件的第一行含有兩個正整數 n 和 q,分別表明有根樹的點數與詢問的個數。class
接下來 n − 1 行,每行描述一條樹上的邊。每行含有兩個整數 u 和 v,表明在節點 u 和 v 之間有一條邊。方法
接下來 q 行,每行描述一個操做。第 i 行含有兩個整數,分別表示第 i 個詢問的 p 和 k。
輸出格式:
輸出 q 行,每行對應一個詢問,表明詢問的答案。
輸入樣例#1:
5 3
1 2
1 3
2 4
4 5
2 2
4 1
2 3
輸出樣例#1:
3
1
3
樣例中的樹以下圖所示:
對於第一個和第三個詢問,合法的三元組有 (2,1,4)、 (2,1,5) 和 (2,4,5)。
對於第二個詢問,合法的三元組只有 (4,2,5)。
全部測試點的數據規模以下:
對於所有測試數據的全部詢問, 1 ≤ p ≤ n, 1 ≤ k ≤ n.
tip:這道題能夠花式作,線段樹合併....(然而蒟蒻我並不會)
其實題目的信息能夠歸納爲這麼幾個條件
1. a和b都是c的祖先節點 2. a和b不是同一個節點 3. a和b在樹中的深度之差的絕對值不超過k
那麼其實咱們能夠分類討論一下,對於\(b\)在\(a\)的上面的狀況,\(c\)只能是\(a\)的子樹中的節點,又由於不能爲\(a\),因此有\(size[a]-1\)種可能,而\(b\)既然在a的上方,那就只有\(min(k,dep[a]-1)\)種取值了
因此很明顯,這一部分的\(ans=min(k,dep[a]-1)\times (size[a]-1)\)
那麼若是\(b\)在\(a\)的下方,則\(c\)只能爲\(b\)的子樹節點,因此對於一個節點,它對答案的貢獻顯然爲\(size[]-1\),咱們把這個答案用前綴和記錄下來,用一種相似差分的方法查詢就好了
怎麼搞?線段樹啊,主席樹啊隨便你亂搞...反正我寫的是主席樹
主席樹的話,由於咱們要求貢獻,那麼確定是要把\(size[]\)當權值插入了,那就只能把\(dfs\)序當下標建樹了
查詢的時候也像線段樹那樣查個差值就行了
而後兩個部分的答案加起來就行了
注意1:若是當前點的深度已是最大深度了,就表明不可能有節點c了,輸出0
注意2:開 long long
#include<bits/stdc++.h> #define in(i) (i=read()) #define il extern inline #define rg register #define mid ((l+r)>>1) #define Min(a,b) ((a)<(b)?(a):(b)) #define Max(a,b) ((a)>(b)?(a):(b)) #define lol long long using namespace std; const lol N=3e5+10; lol read() { lol ans=0, f=1; char i=getchar(); while (i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();} while (i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48), i=getchar(); return ans*f; } lol n,m,cur,maxn,cnt,tot; lol head[N],nex[N<<1],to[N<<1]; lol rt[N],dep[N],size[N],dfn[N]; struct Chair_Tree { lol l,r,v; }t[N<<5]; void add(lol a,lol b) { to[++cur]=b,nex[cur]=head[a],head[a]=cur; to[++cur]=a,nex[cur]=head[b],head[b]=cur; } void insert(lol &u,lol l,lol r,lol pre,lol pos,lol v) { t[u=++tot]=t[pre], t[u].v+=v; if(l==r) return; if(pos<=mid) insert(t[u].l,l,mid,t[pre].l,pos,v); else insert(t[u].r,mid+1,r,t[pre].r,pos,v); } lol query(lol u,lol v,lol l,lol r,lol left,lol right,lol ans=0) { //cout<<l<<" "<<r<<" "<<mid<<endl; if(left<=l && r<=right) return t[v].v-t[u].v; if(left<=mid) ans+=query(t[u].l,t[v].l,l,mid,left,right); if(mid<right) ans+=query(t[u].r,t[v].r,mid+1,r,left,right); return ans; } void init(lol u,lol fa) { size[u]=1; for (lol i=head[u];i;i=nex[i]) { if(to[i]==fa) continue; dep[to[i]]=dep[u]+1; maxn=Max(maxn,dep[to[i]]); init(to[i],u); size[u]+=size[to[i]]; } } void dfs(lol u,lol fa) { dfn[u]+=++cnt; insert(rt[cnt],1,maxn,rt[cnt-1],dep[u],size[u]-1); for (lol i=head[u];i;i=nex[i]) { if(to[i]==fa) continue; dfs(to[i],u); } } int main() { in(n), in(m); for (lol i=1,a,b;i<n;i++) in(a), in(b), add(a,b); dep[1]=1, init(1,0); dfs(1,0); for (lol i=1,p,k,ans;i<=m;i++) { in(p), in(k); ans=(size[p]-1)*Min(k,dep[p]-1); ans+=query(rt[dfn[p]-1],rt[dfn[p]+size[p]-1],1,maxn,dep[p]+1,Min(dep[p]+k,maxn)); if(dep[p]==maxn) ans=0; printf("%lld\n",ans); } }