[bzoj1468][poj1741]Tree[点分治]

可以说是点分治第一题,之前那道的点分治只是模模糊糊,做完这道题感觉清楚了很多,点分治可以理解为每次树的重心(这样会把数分为若干棵子树,子树大小为log级别),然后统计包含重心的整个子树的值减去各个子树的值,这样算出的就是与这个重心有关的情况的答案,比如这道题,求路径,那么就考虑在重心所在的子树中所有的路径减去不过重心的路径就是过重心的路径了。之前重心没找对...poj时间卡的紧就T了。。

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <cmath>
  7 #include <ctime>
  8
  9 using namespace std;
 10
 11 struct Edge
 12 {
 13     int    to,next,w;
 14 }e[210000];
 15
 16 int    n,k,cnt,p[110000],Ans;
 17 int    Son[110000],f[110000],val[110000],depth[110000];
 18 bool    visited[110000];
 19
 20 void    Add_edge(const int x,const int y,const int z)
 21 {
 22     e[++cnt].to=y;
 23     e[cnt].next=p[x];
 24     e[cnt].w=z;
 25     p[x]=cnt;
 26     return ;
 27 }
 28
 29 void    Get_root(const int S,const int fa,const int tot,int & root)
 30 {
 31     Son[S]=1,f[S]=0;
 32     for(int i=p[S];i;i=e[i].next)
 33     {
 34         if(e[i].to==fa || visited[e[i].to])continue;
 35         Get_root(e[i].to,S,tot,root);
 36         Son[S]+=Son[e[i].to];
 37         f[S]=max(f[S],Son[e[i].to]);
 38     }
 39     f[S]=max(f[S],tot-Son[S]);
 40     if(f[S]<f[root])root=S;
 41     return ;
 42 }
 43
 44 void    Get_depth(const int S,const int fa)
 45 {
 46     val[++val[0]]=depth[S];
 47     for(int i=p[S];i;i=e[i].next)
 48     {
 49         if(e[i].to==fa || visited[e[i].to])continue;
 50         depth[e[i].to]=depth[S]+e[i].w;
 51         Get_depth(e[i].to,S);
 52     }
 53     return ;
 54 }
 55
 56 int    Calc(const int S,const int w)
 57 {
 58     depth[S]=w,val[0]=0;
 59     Get_depth(S,0);
 60     sort(val+1,val+val[0]+1);
 61     int    t=0,l,r;
 62     for(l=1,r=val[0];l<r;)
 63     {
 64         if(val[l]+val[r]<=k)t+=r-l,l++;
 65         else    r--;
 66     }
 67     return t;
 68 }
 69
 70 void    TDC(const int S)
 71 {
 72     Ans+=Calc(S,0);
 73     visited[S]=true;
 74     for(int i=p[S];i;i=e[i].next)
 75     {
 76         if(visited[e[i].to])continue;
 77         Ans-=Calc(e[i].to,e[i].w);
 78         int root=0;
 79         Get_root(e[i].to,0,Son[e[i].to],root);
 80         TDC(root);
 81     }
 82     return ;
 83 }
 84
 85 int main()
 86 {
 87     int    x,y,z,i,root;
 88
 89     while(scanf("%d%d",&n,&k) && n && k)
 90     {
 91         root=0,memset(p,0,sizeof(p));cnt=0;
 92         memset(visited,0,sizeof(visited));
 93         Ans=0;
 94         for(i=1;i<n;++i)
 95         {
 96             scanf("%d%d%d",&x,&y,&z);
 97             Add_edge(x,y,z);
 98             Add_edge(y,x,z);
 99         }
100
101         f[0]=0x3f3f3f3f;
102         Get_root(1,0,n,root);
103         TDC(root);
104
105         printf("%d\n",Ans);
106     }
107
108     return 0;
109 }
时间: 2024-12-20 22:09:09

[bzoj1468][poj1741]Tree[点分治]的相关文章

[bzoj1468][poj1741]Tree_点分治

Tree bzoj-1468 poj-1741 题目大意:给你一颗n个点的树,求树上所有路径边权和不大于m的路径条数. 注释:$1\le n\le 4\cdot 10^4$,$1\le m \le 10^9$. 想法:GXZlegend给高一将点分治,去听了之后的第一道模板题. 我们对于一类树上统计问题,除了强大的树形dp之外,我们还有分治.今天听的是点分治: 就是说,我们将所有的链关于一个点分划成两类:过这个点的链,和不过这个点的链.这个点就是根节点,我在任意两颗子树中拎出两个点,他们之间的链

【BZOJ-1468】Tree 树分治

1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1025  Solved: 534[Submit][Status][Discuss] Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k Output 一行,有多少对点之间的距离小于等于k Sample Input 7 1 6 13 6

POJ1741:Tree——点分治

题面 POJ1741 解析  刚学了点分治,练一练模版题 过程就不多说了,主要说说细节 在每次查询下一棵子树时, 传进去的整棵子树大小是上一次的$siz$, 这个数据其实是错的, 但好像并不影响时间复杂度, 这样的话找重心就必须找最大子树最小的点了,否则会错.因此需要存一个当前最大子树最小的点的最大子树的大小, 以及当前的重心, 每次找重心之前,前者要赋为$inf$ 在每次统计以当前点为$lca$的链的答案时, 要先把这个重心加入数组中, 再按$dis$排序, 然后用双指针法或是其他可行的方法统

【BZOJ1468】Tree [点分治]

Tree Time Limit: 10 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description 给你一棵TREE,以及这棵树上边的距离,问有多少对点它们两者间的距离小于等于K. Input 第一行一个n,接下来n-1行边描述管道,按照题目中写的输入,接下来是一个k. Output 仅包括一个整数,表示有多少对点之间的距离小于等于k. Sample Input 7 1 6 13 6 3 9 3 5 7 4 1 3 2 4 20 4

poj1741 Tree 点分治

入门题,算是对树分治有了初步的理解吧. #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using nam

[poj1741]Tree(点分治+容斥原理)

题意:求树中点对距离<=k的无序点对个数. 解题关键:树上点分治,这个分治并没有传统分治的合并过程,只是分成各个小问题,并将各个小问题的答案相加即可,也就是每层的复杂度并不在合并的过程,是在每层的处理过程. 此题维护的是树上路径,考虑点分治. 点分治的模板题,首先设点x到当前子树跟root的距离为,则满足${d_x} + {d_y} \le k$可以加进答案,但是注意如果x,y在同一棵子树中,就要删去对答案的贡献,因为x,y会在其所在的子树中在计算一次.同一棵子树中不必考虑是否在其同一棵子树中的

点分治【bzoj1468】 Tree

点分治[bzoj1468] Tree Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k Output 一行,有多少对点之间的距离小于等于k 点分治开始入门. 点分治,主要是解决形如:给你一棵树,求树上满足XX条件的点对的对数. 所以说应对的问题很多时候都和树形DP相同. 首先告诉自己,分治是高效的算法. 想一下,平时在面对普通的分治问题,每次肯定都是

[LeetCode] Convert Sorted List to Binary Search Tree(分治)

Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. 方法:为了使BST高度平衡,要找链表中的中值作为当前根节点. /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) :

BZOJ.1468.Tree(点分治)

题目链接 BZOJ1468 POJ1741 题意: 计算树上距离<=K的点对数 我们知道树上一条路径要么经过根节点,要么在同一棵子树中. 于是对一个点x我们可以这样统计: 计算出所有点到它的距离dep[],排序后可以O(n)求得<=K的点对数量. 但画个图后我们可以发现,对于在同一棵子树中的路径被重复计算过了.于是我们Ans-=Calc(v),减去一棵子树中的路径答案,但是这并不是之前x到它们的路径,于是给v的dep[]设一个初始值为w(x->v路径权值). 这样x的答案就计算完了,将这