[湖南集訓] 談笑風生 (主席樹)

[湖南集訓] 談笑風生

題目描述

設 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

  1. a、 b 和 c 爲 T 中三個不一樣的點,且 a 爲 p 號節點;ip

  2. a 和 b 都比 c 不知道高明到哪裏去了;get

  3. 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.

Solution

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

Code

#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);
    }
}
相關文章
相關標籤/搜索