关闭

POJ 1741 Tree 点分治

191人阅读 评论(0) 收藏 举报
分类:

时空隧道


题目大意:
给出一棵树,求出这棵树上满足要求的点对有多少个—-要求是两点之间距离小于等于k


分析:
第一想法是n^2暴力,但是很不幸,n<=10000,n^2炸了….
怎么办呢….
我们如果把这棵树看成一棵有根树,那么这些点对有两种情况—-一种是两个点在两棵子树中,一种是在一颗子树中…
所以我们可以求出dis[i](所有点到重心的距离—为什么是重心呢…防止退化成n^2),然后在dis数组中On的求出满足要求的点对,然后递归处理它的子树,但是这样会有重复的,所以要减去子树中的ans,也就是说只有路径经过重心的点对才会对答案有贡献


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=10000+5;
int hd[maxn],to[maxn*2],nxt[maxn*2],w[maxn*2],cnt,n,barycentre,MIN,ans,dis[maxn],size[maxn],MAX[maxn],num,k;
bool vis[maxn];
inline void add(int x,int y,int s){
    w[cnt]=s;
    to[cnt]=y;
    nxt[cnt]=hd[x];
    hd[x]=cnt++;
}
inline void SIZE(int root,int fa){
    size[root]=1,MAX[root]=0;
    for(int i=hd[root];i!=-1;i=nxt[i])
        if(to[i]!=fa&&!vis[to[i]])
            SIZE(to[i],root),size[root]+=size[to[i]],MAX[root]=max(MAX[root],size[to[i]]);
}
inline void findroot(int u,int root,int fa){
    MAX[root]=max(MAX[root],size[u]-size[root]);
    if(MIN>MAX[root])
        MIN=MAX[root],barycentre=root;
    for(int i=hd[root];i!=-1;i=nxt[i])
        if(!vis[to[i]]&&to[i]!=fa)
            findroot(u,to[i],root);
}
inline void DIS(int root,int fa,int d){
    dis[++num]=d;
    for(int i=hd[root];i!=-1;i=nxt[i])
        if(to[i]!=fa&&!vis[to[i]])
            DIS(to[i],root,d+w[i]);
}
inline int calc(int root,int d){
    num=0;
    DIS(root,-1,d);
    sort(dis+1,dis+num+1);
    int res=0,x=1,y=num;
    while(x<y){
        while(x<y&&dis[x]+dis[y]>k)
            y--;
        res+=y-x;
        x++;
    }
    return res;
}
inline void dfs(int root){
    MIN=n;
    SIZE(root,-1);
    findroot(root,root,-1);
    ans+=calc(barycentre,0);
    vis[barycentre]=1;
    for(int i=hd[barycentre];i!=-1;i=nxt[i])
        if(!vis[to[i]])
            ans-=calc(to[i],w[i]),dfs(to[i]);
}
signed main(void){
    while(scanf("%d%d",&n,&k)&&!(!n&&!k)){
        ans=cnt=0,memset(hd,-1,sizeof(hd));
        for(int i=1,x,y,s;i<n;i++)
            scanf("%d%d%d",&x,&y,&s),add(x,y,s),add(y,x,s);
        memset(vis,0,sizeof(vis));
        dfs(1);
        printf("%d\n",ans);
    }
    return 0;
} 

by >_< neighthorn

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:42166次
    • 积分:2190
    • 等级:
    • 排名:第17950名
    • 原创:170篇
    • 转载:5篇
    • 译文:0篇
    • 评论:32条
    博客专栏
    文章分类
    最新评论