POJ 1741 Tree 点分治

原创 2016年08月31日 15:04:39

时空隧道


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

版权声明:转载请注明出处---by 小雪刺

POJ 1741 Tree【Tree,点分治】

树上的算法真的很有意思……哈哈。 给一棵边带权树,问两点之间的距离小于等于K的点对有多少个。 将无根树转化成有根树进行观察。满足条件的点对有两种情况:两个点的路径横跨树根,两个点位于同一颗子树中。...
  • yang_7_46
  • yang_7_46
  • 2013年08月14日 16:27
  • 12978

树分治(点分治模板)poj-1741 Tree

首先讲解一下树分治,以下的内容转自:http://blog.sina.com.cn/s/blog_6d5aa19a0100o73m.html 对于一棵有根树, 树中满足要求的一个数对所对应的一条...
  • u010660276
  • u010660276
  • 2015年04月07日 15:22
  • 5063

POJ 1741 Tree(树的点分治、树形dp、男人八题)

【题意】求树上距离小于等于K的点对有多少个 n有10000,所以必须卡到nlogn附近。变得尤为麻烦。 首先,一对符合要求的点,它们经过的路径中一定可以找到一个根节点。 每次我们都找以这个根为“...
  • AngOn823
  • AngOn823
  • 2016年08月24日 16:55
  • 521

【POJ1741】Tree 树分治 模板咯?

题意: 给你一棵无根树,求有多少点对之间距离 题解: 树分治。 然后对于一个重心X,我们把它的所有子树中的所有点存到结构体数组中。 结构体中存距离和子树编号。 第一遍sort,我们双指...
  • Vmurder
  • Vmurder
  • 2015年03月16日 11:19
  • 1721

【POJ】1741 Tree 点分治

题目大意:给出一棵树,边有权值,求满足dis(i,j) 点分治。 对于一条路径,要么经过根,要么在某棵子树内,所以我们使用点分治。 我们只用考虑经过根的情况,对于在某棵子树内这种情况,使用分...
  • u013598409
  • u013598409
  • 2015年09月20日 08:26
  • 299

【POJ】1741 Tree 点分治

传送门:【POJ】1741 Tree 题目分析:点分治第一题!
  • u013368721
  • u013368721
  • 2014年09月18日 10:53
  • 619

POJ 1741 Tree(点分治)

题意: N≤104的一棵树,(u,v,l),l≤103三元组描述这棵树,求dis(u,v)≤k,u≠v的点对数,k≤109N\leq 10^4的一棵树, (u,v,l), l \le 10^3三元...
  • lwt36
  • lwt36
  • 2015年12月18日 02:39
  • 294

POJ 1741 Tree——点分治

题意:给定一棵树,求合法点对的个数,合法点对定义为:两点之间的距离不超过k 思路: 1求树的重心 2以树的重心为根,求此次划分中其余的点到根节点的距离 3计算此次划分的合法点对 4减去在同一...
  • hao_zong_yin
  • hao_zong_yin
  • 2017年11月28日 17:38
  • 59

POJ 1741 Tree 树的分治(点分治)

题目大意:给出一颗无根树和每条边的权值,求出树上两个点之间距离 思路:树的点分治。利用递归和求树的重心来解决这类问题。因为满足题意的点对一共只有两种: 1.在以该节点的子树中且不经过该节点...
  • jiangyuze831
  • jiangyuze831
  • 2014年10月11日 16:00
  • 658

POJ 1741 Tree (树分治之点分治)

题目大意: 给出一棵树, 点数n 大致思路: 马上就要区域赛了...走前看点点分治的题...遵循昊哥的教导 这个题就是点分治很裸的一个模型了 所谓点分治, 每次将问题递归到子树上解...
  • u013738743
  • u013738743
  • 2015年10月13日 23:13
  • 303
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ 1741 Tree 点分治
举报原因:
原因补充:

(最多只允许输入30个字)