Awesome Shawarma Gym - 101991A(點分治)

Fouad has a raw awesome shawarma, and he is in a city which is represented as an undirected tree. He heard that there is a magical oven that will cook the Shawarma, to make it so delicious. However, In order to acquire the magical oven, there need to be two conditions that should be satisfied in this city:

  • One extra edge that must be added to join two different nodes in the tree (It is allowed to join two nodes, which were previously connected by a direct edge).
  • The number of bridges after adding the new edge should be between [L,R]
  • inclusively.

Please help Fouad to acquire the magical oven, to cook the awesome shawarma by counting in how many ways he can add an edge that satisfies the conditions above.

大意是:給你一棵樹,問有多少種方案在加一條邊後使圖中橋點數量在·[l,r]範圍內。

容易想到,樹加一條邊後會產生一個環,所有不在環上的邊都是橋。滿足條件的環的長度是[n-r,n-l],也就是求樹上要多少距離[n-r-1,n-l-1]的點對,這就是點分治問題了。

無奈不會點分治,只能去學了一波。

暴力的思路,枚舉每個點作爲根節點,求出所有子節點到它的距離,計算出小於k的距離,然後容斥去重,但是在一條鏈的時候會T。點分治就是每次求出樹的重心,以重心作爲根節點。

#include <bits/stdc++.h>

using namespace std;
#define ll long long
const int N = 1e5+123;
vector<int>son[N];
vector<int>path;
int s,root;
ll ans=0;
int vis[N],sum[N],mson[N];
void getroot(int u,int fa){
    sum[u]=1;mson[u]=0;
    for(int i=0;i<(int)son[u].size();i++){
        int v=son[u][i];
        if(v==fa||vis[v])continue;
        getroot(v,u);
        sum[u] += sum[v];
        mson[u]=max(mson[u],sum[v]);
    }
    mson[u]=max(mson[u],s-sum[u]);
    if(mson[u]<mson[root])root=u;
}
void getdis(int u,int fa,int dis){
    path.push_back(dis);
    for(int i=0;i<(int)son[u].size();i++){
        int v=son[u][i];
        if(v==fa||vis[v])continue;
        getdis(v,u,dis+1);
    }
}
ll cal(int u,int dis,int K){
    ll res=0;
    path.clear();
    getdis(u,0,dis);
    sort(path.begin(),path.end());
    for(int i=0,j=path.size()-1;i<j;i++){
        while(path[i]+path[j]>K&&i<j)j--;
        res+=j-i;
    }
    return res;
}
void divide(int u,int K){
    ans += cal(u,0,K);
    vis[u]=1;
    for(int i=0;i<(int)son[u].size();i++){
        int v=son[u][i];
        if(vis[v])continue;
        ans -= cal(v,1,K);
        mson[0]=s=sum[v];root=0;
        getroot(v,0);divide(root,K);

    }
}
ll solve(int n,int K){
    if(K<=0)return 0;
    ans=0;
    memset(vis,0,sizeof(vis));
    mson[0]=s=n;root=0;
    getroot(1,-1);divide(root,K);
    return ans;
}
int main()
{
    //freopen("awesome.in","r",stdin);
    int T,L,R,n,x,y;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d %d",&n, &L,&R);
        for(int i=1;i<=n;i++)son[i].clear();
        for(int i=0;i<n-1;i++){
            scanf("%d %d",&x,&y);
            son[x].push_back(y);
            son[y].push_back(x);
        }
        printf("%lld\n",solve(n,n-L-1)-solve(n,n-R-2));

    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章