poj1741(入门点分治)

Posted frankchen831x

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj1741(入门点分治)相关的知识,希望对你有一定的参考价值。

题目链接:https://vjudge.net/problem/POJ-1741

题意:给出一棵树,求出树上距离不超过k的点对数量。

思路:点分治经典题。先找重心作为树根,然后求出子树中所有点到重心的距离dis[i],那么所有组合为dis[i]+dis[j]<=k,其中不合法组合为在重心的同一个子树内的情况,所以要减去在重心的子树中仍满足dis[i]+dis[j]<=k的情况。

AC代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int inf=0x3f3f3f3f;
const int maxn=10005;
struct node1
    int v,w,nex;
edge[maxn<<1];

struct node2
    int x,y;
arr[maxn];

int n,k,cnt,ans,head[maxn],sz[maxn],mson[maxn],Min,root,size;
int vis[maxn],t,tt,dis[maxn],pre[maxn];

void adde(int u,int v,int w)
    edge[++cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nex=head[u];
    head[u]=cnt;


void getroot(int u,int fa)
    sz[u]=1,mson[u]=0;
    for(int i=head[u];i;i=edge[i].nex)
        int v=edge[i].v;
        if(vis[v]||v==fa) continue;
        getroot(v,u);
        sz[u]+=sz[v];
        if(sz[v]>mson[u]) mson[u]=sz[v];
    
    if(size-sz[u]>mson[u]) mson[u]=size-sz[u];
    if(mson[u]<Min) Min=mson[u],root=u;


void getdis(int u,int fa,int len)
    dis[++t]=len;
    for(int i=head[u];i;i=edge[i].nex)
        int v=edge[i].v;
        if(vis[v]||v==fa) continue;
        getdis(v,u,len+edge[i].w);
    


void solve(int x,int y,int f)
    t=0;
    getdis(x,0,y);
    sort(dis+1,dis+t+1);
    tt=0,dis[0]=-1,pre[0]=0;
    for(int i=1;i<=t;++i)
        if(dis[i]!=dis[i-1]) arr[++tt].x=dis[i],arr[tt].y=1,pre[tt]=pre[tt-1]+1;
        else ++arr[tt].y,++pre[tt];
    for(int i=1;i<=tt&&arr[i].x<=k/2;++i)
        ans+=(arr[i].y-1)*arr[i].y/2*f;
    for(int i=1;i<=tt&&arr[i].x<k/2;++i)
        int l=i+1,r=tt,mid;
        while(l<=r)
            mid=(l+r)>>1;
            if(arr[i].x+arr[mid].x<=k) l=mid+1;
            else r=mid-1;
        
        ans+=(arr[i].y)*(pre[r]-pre[i])*f;
    


void fenzhi(int u,int ssize)
    vis[u]=1;
    solve(u,0,1);
    for(int i=head[u];i;i=edge[i].nex)
        int v=edge[i].v;
        if(vis[v]) continue;
        solve(v,edge[i].w,-1);
        Min=inf,root=0;
        size=sz[v]<sz[u]?sz[v]:(ssize-sz[u]);
        getroot(v,0);
        fenzhi(root,size);
    


int main()
    while(scanf("%d%d",&n,&k),n||k)
        cnt=ans=0;
        for(int i=0;i<=n;++i)
            head[i]=0,vis[i]=0;
        for(int i=1;i<n;++i)
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            adde(u,v,w);
            adde(v,u,w);
        
        Min=inf,root=0,size=n;
        getroot(1,0);
        fenzhi(root,n);
        printf("%d\n",ans);
    

 

以上是关于poj1741(入门点分治)的主要内容,如果未能解决你的问题,请参考以下文章

poj 1741 树的点分治(入门)

poj1741+poj1987+poj2114——点分治入门题集合

POJ 1741 Tree(树的点分治,入门题)

poj1741 Tree 点分治

POJ 1741 树分治(点分治模板题)

POJ 1741 Tree(点分治)