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 点分治 树上问题

大家都很强,可与之共勉函数对应关系写错, 调了两个小时, FUKK。 大致思路:点分支。 找以每一个节点(其实不是每一个)为根节点的重心, 用dis[ ]表示经过重心的每一条链的长度。但是计算的时...

POJ 1741 Tree [树上点分治]

给出一棵树,问树上点对所代表的简单路径长度

POJ 1741 Tree DP+树的点分治

POJ 1741 Tree DP+树的点分治
  • wzq_QwQ
  • wzq_QwQ
  • 2015年07月22日 14:54
  • 703

poj1741 tree 点分治

poj1741 tree 把这几天写的东西上传一下 写博客的意义大概就是整理一下思路 以及方便日后复习 不得不说 把代码放在文件夹里 做完我是不会过目的 写博客 或许会增加我的成就感 从而...
  • yxr0105
  • yxr0105
  • 2016年01月27日 13:48
  • 207

POJ 1741:Tree (淀粉质(点分治

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 22376   Accepted...
  • zjq_01
  • zjq_01
  • 2017年06月08日 17:00
  • 69

POJ 1741 Tree(树上的点分治)

题意:一棵树,边上有权值,求2点之间距离小于等于k的对数。 很经典的点分治问题,理解后思路比较清晰,点对分为3种情况,第1种是在子树中,这就是分治递归的过程。第2种就是子树里的点到根节点距离小于等于...

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
  • 277

POJ1741——Tree 基于点的分治

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 11229   Accepted...

POJ 1741 Tree (树上点分治)(楼教主男人八题之一)

题目地址:POJ 1741 树分治第一发! 树分治详情请看漆子超的国家集训队论文,论文传送门 树分治裸题。 代码如下:#include #include #include #includ...

poj1741 Tree点分治

点分治入门题. 每次统计完到重心的dis之后sort一遍统计答案.#include #include #include using namespace std; const int maxn=100...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ 1741 Tree 点分治
举报原因:
原因补充:

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