poj1741 Tree(点分治)

题目链接:http://poj.org/problem?id=1741

题意:求树上两点之间距离小于等于k的点对的数量

思路:点分治模板题,推荐一篇讲的非常好的博客:https://blog.csdn.net/qq_39553725/article/details/77542223

实现代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define inf 0x7fffffff
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
const int M = 1e5+10;
struct node{
    int to,w,next;
}e[M<<2];
int n,m;
int vis[M],dis[M],d[M],siz[M],f[M],cnt,head[M],sum,root,k,ans;
void init(){
    cnt = 0;
    ans = 0;
    memset(head,0,sizeof(head));
    memset(vis,0,sizeof(vis));
}

void add(int u,int v,int w){
    e[++cnt].to=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;
}


void get_root(int u,int fa){
    siz[u] = 1; f[u] = 0;
    for(int i = head[u];i;i=e[i].next){
        int v = e[i].to;
        if(v!=fa&&!vis[v]){
            get_root(v,u);
            siz[u] += siz[v];
            f[u] = max(f[u],siz[v]);
        }
    }
    // cout<<"sum:  "<<sum-siz[v]<<endl
    f[u] = max(f[u],sum - siz[u]);
    if(f[u] < f[root]) root = u;
    return ;
}

void get_dis(int u,int fa){
    dis[++dis[0]] = d[u];
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to;
        if(v != fa&& !vis[v]){
            d[v] = d[u] + e[i].w;
            get_dis(v,u);
        }
    }
    return;
}

int cal(int u,int c){
    d[u] =  c; dis[0] = 0;
    get_dis(u,0);
    sort(dis+1,dis+dis[0]+1);
    int l = 1,r = dis[0],sum = 0;
    while(l < r){
        if(dis[l] + dis[r] <= k){
            sum+=r-l;
            l ++;
        }
        else r--;
    }
    return sum;
}

void solve(int u){
    ans += cal(u,0);
    vis[u] = 1;
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to;
        if(!vis[v]){
            ans -= cal(v,e[i].w);
            sum = siz[v] ;
            root = 0;
            get_root(v,0);
            solve(root);
        }
    }
}
int main()
{
    int u,v,w;
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    while(cin>>n>>k){
    if(n==0&&m==0) break;
    init();
    for(int i = 1;i <= n-1;i ++){
        cin>>u>>v>>w;
        add(u,v,w); add(v,u,w);
    }
    f[0] = inf;
    sum = n;
    root = 0;
    get_root(1,0);
    solve(root);
    cout<<ans<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kls123/p/9317113.html