POJ1741 Tree 点分治

问题描述

POJ1741


题解

题意是求树上满足两点之间距离 \(dis \le k\) 的点对 \((x,y)\) 的数目。

点分治。


\(\mathrm{Code}\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

template <typename Tp>
void read(Tp &x){
    x=0;char ch=1;int fh;
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') ch=getchar(),fh=-1;
    else fh=1;
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    x*=fh;
}

const int maxn=10007;
const int maxm=20007;
const int INF=0x3f3f3f3f;

int n,k;
int Head[maxn],to[maxm],Next[maxm],w[maxm],tot;
int size[maxn],mx,sz,root;

int ans,dis[maxn];
int q[maxn],l,r;

bool del[maxn];

void reset(){
    memset(Head,0,sizeof(Head));
    memset(Next,0,sizeof(Next));
    memset(del,0,sizeof(del));
    tot=ans=0;
}

void add(int x,int y,int z){
    to[++tot]=y,Next[tot]=Head[x],Head[x]=tot,w[tot]=z;
}

void Init(){
    read(k);
    for(int i=1,x,y,z;i<n;i++){
        read(x);read(y);read(z);
        add(x,y,z);add(y,x,z);
    }
}

void getdis(int x,int fa){
    q[++r]=dis[x];
    for(int i=Head[x];i;i=Next[i]){
        int y=to[i];
        if(y==fa||del[y]) continue;
        dis[y]=dis[x]+w[i];
        getdis(y,x);
    }
}

int calc(int x,int val){
    r=0;dis[x]=val;
    getdis(x,0);
    int res=0;l=1;
    sort(q+1,q+r+1);
    while(l<r){
        if(q[l]+q[r]<=k) res+=r-l,++l;
        else --r;
    }
    return res;
}

void getroot(int x,int fa){
    size[x]=1;int num=0;
    for(int i=Head[x];i;i=Next[i]){
        int y=to[i];
        if(y==fa||del[y]) continue;
        getroot(y,x);
        size[x]+=size[y];
        num=max(num,size[y]);
    }
    num=max(num,sz-size[x]);
    if(num<mx) mx=num,root=x;
}

void dfs(int x){
    ans+=calc(x,0);del[x]=1;
    for(int i=Head[x];i;i=Next[i]){
        int y=to[i];
        if(del[y]) continue;
        ans-=calc(y,w[i]);
        sz=size[y],mx=INF;
        getroot(y,0);dfs(root);
    }
}

void solve(){
    sz=n,mx=INF;
    getroot(1,0);
    dfs(root);
    printf("%d\n",ans);
}

int main(){
    while(1){
        read(n);if(!n) return 0;
        reset();Init();solve();
    }
    return 0;
}
全部评论

相关推荐

球球别再泡了:坏,我单9要了14
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务