P4178 Tree(点分治)

没想到一发直接过了啊
思路

点分治

二分小于等于k的位置即可

代码
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int middis[40010],midcnt,n,k,u[40010<<1],v[40010<<1],w[40010<<1],cnt,fir[40010],nxt[40010<<1],sz[40100],f[40100],root,vis[40100],Siz;
long long ans=0;
void addedge(int ui,int vi,int wi){
    ++cnt;
    u[cnt]=ui;
    v[cnt]=vi;
    w[cnt]=wi;
    nxt[cnt]=fir[ui];
    fir[ui]=cnt;
}
void findroot(int u,int fa){
    f[u]=1;
    sz[u]=1;
    for(int i=fir[u];i;i=nxt[i]){
        if(v[i]==fa||vis[v[i]])
            continue;
        findroot(v[i],u);
        sz[u]+=sz[v[i]];
        f[u]=max(f[u],sz[v[i]]);
    }
    f[u]=max(Siz-f[u],f[u]);
    if(f[root]>f[u])
        root=u;
}
void getdis(int u,int d,int fa){
    middis[++midcnt]=d;
    for(int i=fir[u];i;i=nxt[i]){
        if(v[i]==fa||vis[v[i]])
            continue;
        getdis(v[i],d+w[i],u);
    }
}
int look(int l,int k){
    int ans=0,r=midcnt;
    while(l<=r){
        int mid=(l+r)>>1;
        if(middis[mid]<=k)
            ans=mid,l=mid+1;
        else
            r=mid-1;
    }
}
int solve(int u,int d,int fa){
    midcnt=0;
    getdis(u,d,fa);
    sort(middis+1,middis+midcnt+1);
    int l=1,ans=0;
    // ans+=look(1,k);
    while(l<midcnt&&k-middis[l]>=middis[l]){
        int lx=look(l+1,k-middis[l]);
        if(lx>l)
            ans+=lx-l-1;
        l++;
    }
    return ans;
}
void divide(int u){
    // printf("%d\n",u);
    // getchar();
    vis[u]=true;
    ans+=solve(u,0,0);
    // printf("ans=%d\n",ans);
    for(int i=fir[u];i;i=nxt[i]){
        if(vis[v[i]])
            continue;
        ans-=solve(v[i],w[i],u);
        root=0;
        Siz=sz[v[i]];
        findroot(v[i],u);
        divide(root);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++){
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        addedge(a,b,c);
        addedge(b,a,c);
    }
    scanf("%d",&k);
    Siz=n;
    f[0]=0x3f3f3f3f;
    findroot(1,0);
    divide(root);
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/dreagonm/p/10093323.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
K-D Tree(K-Dimensional Tree)算法是一种基于分治法的数据结构,用于高维空间的搜索和排序。它的基本思想是将多维空间中的以某种方式分割成更小的子空间,然后在每个子空间中递归地进行搜索。这样可以大大降低搜索的复杂度。 具体来说,K-D Tree算法可以分为以下几步: 1. 选择一个维度,将数据按照该维度的值进行排序。 2. 找到该维度的中位数,将其作为当前节,并将数据分为左右两个子集。 3. 递归地构建左子树和右子树,每次选择一个新的维度进行划分。 4. 最终得到一个K-D Tree。 在搜索时,我们可以从根节开始,按照一定的规则向下遍历,直到找到目标或者无法继续向下搜索。具体的规则是: 1. 如果目标在当前节的左子树中,则继续向左子树搜索。 2. 如果目标在当前节的右子树中,则继续向右子树搜索。 3. 如果目标和当前节在选定的维度上的值相等,则说明已经找到目标分治法是一种常见的算法思想,它将一个大规模的问题分解成若干个小规模的子问题,每个子问题独立地求解,然后将这些子问题的解合并起来得到原问题的解。分治法通常包含三个步骤:分解、求解、合并。 具体来说,分治法可以分为以下几步: 1. 分解:将原问题分成若干个子问题,每个子问题规模较小且结构与原问题相同。 2. 求解:递归地求解每个子问题,直到问题规模足够小可以直接求解。 3. 合并:将所有子问题的解合并成原问题的解。 分治法的优是可以有效地降低算法的时间复杂度。但是它的缺是需要额外的空间来存储子问题的解,而且分解和合并的过程也需要耗费一定的时间。因此,需要根据实际情况选择合适的算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值