POJ 1741 Tree 点分治

来源:互联网 发布:杭州月嫂哪家好 知乎 编辑:程序博客网 时间:2024/05/21 08:47

时空隧道


题目大意:
给出一棵树,求出这棵树上满足要求的点对有多少个—-要求是两点之间距离小于等于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
原创粉丝点击