Tree bzoj-1468 poj-1741

    题目大意:给你一颗n个点的树,求树上所有路径边权和不大于m的路径条数。

    注释:$1\le n\le 4\cdot 10^4$,$1\le m \le 10^9$。

      想法:GXZlegend给高一讲点分治,去听了之后的第一道模板题。

        我们对于一类树上统计问题,除了强大的树形dp之外,我们还有分治。今天听的是点分治:

        就是说,我们将所有的链关于一个点分划成两类:过这个点的链,和不过这个点的链。这个点就是根节点,我在任意两颗子树中拎出两个点,他们之间的链,就是经过根节点的链。紧接着,我们递归处理这个过程。对于每一个子树,钦定一个根节点,然后求这个子树中经过子树的钦定节点且满足条件的链。那么,这个钦定节点如何选取?显然,树链统计问题可以O(n*n)枚举所有链,那么,我要使得这样的钦定节点可以降低枚举复杂度。于是,我在递归时要尽量使得所有的子树尽量差不多,这样时间复杂度会降下来。故,我们可以钦定树的重心,这样每次递归都求重心,时间复杂度为O(n*logn)。每一次递归的时候重新更新所有节点的所有信息,把当过重心的节点通过mark的方式删掉,就完成了点分治的过程。

        剩下的,就是一些代码:

      找重心的时候顺便更新当前子树的size

void getroot(int pos,int fa)
//与其函数名叫做getroot,倒不如数get_original,因为每一次递归都必须求重心和节点size
{f[pos]=0;size[pos]=1;for(int i=head[pos];i;i=nxt[i]){if(to[i]==fa||vis[to[i]]) continue;getroot(to[i],pos);size[pos]+=size[to[i]];f[pos]=max(f[pos],size[to[i]]);}f[pos]=max(f[pos],sn-size[pos]);if(f[root]>f[pos]) root=pos;
}

      回归本题,我们期望寻找到所有的链,那么我就可以在钦定完节点之后,从所有子树的所有节点中拎出所有节点的deep,我只需要找到这些deep之间和小于等于m的(先不考虑同一颗子树中的情况)。找出这些deep之后,用双指针即可求出当前链假装过重心(同一颗子树有算重的情况)的个数,然后运用容斥原理,减掉每一颗子树中的情况即可。

      由于双指针的时候需要排序,所以总的之间复杂度是$O(n\cdot log^2n)$

    最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 40010
using namespace std;
int to[N<<1],head[N],cnt,nxt[N<<1],val[N<<1];
int f[N],root,m,deep[N],size[N],sn,d[N],tot,ans;
bool vis[N];
inline void add(int x,int y,int z)
{//用cnt是因为后面顺手写了totto[++cnt]=y;val[cnt]=z;nxt[cnt]=head[x];head[x]=cnt;
}
void getroot(int pos,int fa)
//与其函数名叫做getroot,倒不如数get_original,因为每一次递归都必须求重心和节点size
{f[pos]=0;size[pos]=1;for(int i=head[pos];i;i=nxt[i]){if(to[i]==fa||vis[to[i]]) continue;getroot(to[i],pos);size[pos]+=size[to[i]];f[pos]=max(f[pos],size[to[i]]);}f[pos]=max(f[pos],sn-size[pos]);if(f[root]>f[pos]) root=pos;
}
void getdeep(int pos,int fa)//deep是当前节点到重心的路径边权和
{d[++tot]=deep[pos];//之后需要双指针for(int i=head[pos];i;i=nxt[i]){if(to[i]==fa||vis[to[i]]) continue;deep[to[i]]=deep[pos]+val[i],getdeep(to[i],pos);}
}
int calc(int pos)//双指针求过pos的满足条件数
{tot=0;getdeep(pos,0);sort(d+1,d+tot+1);int i=1,j=tot,sum=0;while(i<j){if(d[i]+d[j]<=m) sum+=j-i,i++;else j--;}return sum;
}
void dfs(int pos)
{deep[pos]=0;vis[pos]=1;ans+=calc(pos);for(int i=head[pos];i;i=nxt[i]){if(!vis[to[i]]){deep[to[i]]=val[i];ans-=calc(to[i]);//单步容斥sn=size[to[i]];//求重心时用得到root=0;//当前子树重心rootgetroot(to[i],0);//现在root是重心了dfs(root);}}
}
int main()
{int n;scanf("%d",&n);for(int i=1;i<n;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);add(x,y,z);add(y,x,z);}cnt=0,ans=0;scanf("%d",&m);f[0]=0x7f7f7f7f;//绝对不能让0是root的神奇操作qwqsn=n;root=0,getroot(1,0),dfs(root);printf("%d\n",ans);return 0;
}

    小结:错误在于对点分治理解不够深刻(其实是双指针的时候j++导致全盘爆炸).

      点分治是处理树上统计问题的好方法。鸣谢GXZlegend

转载于:https://www.cnblogs.com/ShuraK/p/8782663.html

[bzoj1468][poj1741]Tree_点分治相关推荐

  1. poj1741 Tree 点分治

    入门题,算是对树分治有了初步的理解吧. #include<iostream> #include<cstdio> #include<cstring> #include ...

  2. poj-1741(树分治 点权)

    题目链接 思路: //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> ...

  3. 树分治树链剖分相关题目讨论

    预备知识 树分治,树链剖分 poj1741 •一棵有n个节点的树,节点之间的边有长度.方方方想知道,有多少个点对距离不超过m 题解 点分治模板题.详见我早上写的http://www.cnblogs.c ...

  4. POJ1741 Tree(树分治——点分治)题解

    题意:给一棵树,问你最多能找到几个组合(u,v),使得两点距离不超过k. 思路:点分治,复杂度O(nlogn*logn).看了半天还是有点模糊. 显然,所有满足要求的组合,连接这两个点,他们必然经过他 ...

  5. POJ1741 Tree 树中点对统计【树分治入门】

    算法合集之<分治算法在树的路径问题中的应用> 论文下载地址 树被定义为没有圈的连通图,有几个性质 在树中去掉一条边后,得到的图是不连通的 在树中添加一条边后,一定存在一条边 树的每一对顶点 ...

  6. 树上分治详解 超级详细(附带例题 poj1741(给了题目))

    例题大概意思就是有一颗有 n 个顶点的树,其中连接顶点 a_i 和 b_i 的边 i 的长度为 l ,然后统计最短距离不超过 k 的顶点的对数 (虽然篇幅比较长,但是看完会有收获的) 树上的分治,与其 ...

  7. POJ1741:Tree——题解+树分治简要讲解

    http://poj.org/problem?id=1741 题目大意:给一棵树,求点对间距离<=k的个数. -------------------- 以这道题为例记录一下对于树分治的理解. 树 ...

  8. 【POJ1741】Tree,第一次的点分治

    Time:2016.08.04 Author:xiaoyimi 转载注明出处谢谢 注意:代码中递归子树时对子树大小的计算有误,虽然可以保证正确性但是会使得求得的子树重心并不正确,可能会被卡掉 传送门 ...

  9. POJ1741 Tree(点分治)

    嘟嘟嘟 没错,这一道最经典的点分治模板题. 题意:求树上两点间距离\(\leqslant k\)的点对个数. 点分治这东西我好早就听说了,然后一两个月前也学了一下,不过只是刷了个模板,没往深处学. 对 ...

  10. [poj1741 Tree]树上点分治

    题意:给一个N个节点的带权树,求长度小于等于K的路径条数 思路:选取一个点作为根root,假设f(root)是当前树的答案,那么答案来源于两部分: (1)路径不经过root,那么就是完全在子树内,这部 ...

最新文章

  1. oracle外部表导入,oracle 外部表导入时间日期类型数据
  2. 西南交通大学计算机基础实验,西南交通大学实验教学平台-关于
  3. 这 24 个高频存储问题,你一定要知道
  4. PyTorch 1.0 中文官方教程:使用 PyTorch 进行图像风格转换
  5. 命令行怎么关闭自动修复此计算机,cmd重启命令(win10怎么跳过自动修复)
  6. 我的技术心病(转贴)
  7. SVN+网站服务器同步更新
  8. 强化学习用于电力系统决策与控制(一)——频率调整
  9. 基于JQUERY的WEB在线流程图设计器GOOFLOW 0.6版
  10. 校园二手交易平台设计总览
  11. QQ微信实时消息转发图片文件视频语音互联机器人自动发消息
  12. 《未来世界的幸存者-阮一峰》系列分享专栏
  13. ansible之判断语句jinja2模板的使用 与roles角色的配置使用
  14. 数据挖掘——时间序列算法之ARCH模型
  15. StellarWP 收购 LearnDash 学习管理系统
  16. 如何关闭华为自动杀进程_如何彻底关闭windows 10的 自动更新
  17. 电脑wps可以语音录入吗_怎样用word进行语音录入文字
  18. Subresource Integrity 介绍
  19. php设计模式经典实例集合
  20. rtems 文件系统(15)-jffs2 研究(5)--测试打印记录mkdir,嵌套mkdir

热门文章

  1. 双目测距(四)--罗德里格斯变换
  2. memmove、memcpy和memccpy简介
  3. 3. 吴恩达机器学习课程-作业3-多分类和神经网络
  4. C语言:有N个学生,每个学生有3门课程的成绩,从键盘输入以上数据(包括学号、姓名、3门课程的成绩),计算出平均成绩,将原有数据和计算出的平均成绩存放在磁盘文件stu_list.txt中。
  5. pytest源码_pytest文档60pytest.main()的使用
  6. PAT (Basic Level) Practice1013 数素数
  7. clickhouse HDFS引擎
  8. 搭建迁移训练Slim框架环境
  9. Zephry_GPIO的中断使用详解以及中断原理
  10. 如何使用phpMQTT连接阿里云微服务消息队列for IoT