【树的点分治——模板】

  1 #define Troy 9/28/2017
  2
  3 #define inf 0x7fffffff
  4
  5 #include "cstdio"
  6 #include "cstring"
  7 #include "algorithm"
  8 using std::sort;
  9
 10 typedef long long ll;
 11 ll ans;
 12
 13 inline int max(int a,int b){return a>b?a:b;}
 14 inline int min(int a,int b){return a<b?a:b;}
 15 inline int read(){
 16     int s=0,k=1;char ch=getchar();
 17     while(ch<‘0‘|ch>‘9‘)    ch==‘-‘?k=-1:0,ch=getchar();
 18     while(ch>47&ch<=‘9‘)    s=s*10+(ch^48),ch=getchar();
 19     return s*k;
 20 }
 21 const int N=10050;
 22
 23 struct edges {
 24     int v,w;edges *last;
 25 }edge[N<<1],*head[N];int cnt;
 26 inline void push(int u,int v,int w){
 27     edge[++cnt]=(edges){v,w,head[u]};head[u]=edge+cnt;
 28     edge[++cnt]=(edges){u,w,head[v]};head[v]=edge+cnt;
 29 }
 30 bool del[N];int n,K;
 31 int top;bool vis[N];
 32
 33 inline void clear(){
 34     cnt=0;ans=0;
 35     memset(vis,0,sizeof(vis));
 36     memset(head,0,sizeof(head));
 37 }
 38
 39 int size[N],heavy[N],root,num,dis[N];
 40
 41 inline void dfs_size(int x,int fa){
 42     size[x]=1;
 43     heavy[x]=0;
 44     for(edges *i=head[x];i;i=i->last)   if(vis[i->v]||i->v==fa)  continue;
 45     else{
 46         dfs_size(i->v,x);
 47         heavy[x]=max(size[i->v],heavy[x]);
 48         size[x]+=size[i->v];
 49     }
 50 }
 51
 52 inline void find_root(int tot,int x,int fa){
 53     heavy[x]=max(tot-size[x],heavy[x]);
 54     if(heavy[x]<top)    top=heavy[x],root=x;
 55     for(edges *i=head[x];i;i=i->last){
 56         if(i->v==fa|vis[i->v])  continue;
 57         find_root(tot,i->v,x);
 58     }
 59 }
 60
 61 inline void dfs_dis(int x,int d,int fa){
 62     dis[num++]=d;
 63     for(edges *i=head[x];i;i=i->last){
 64         if(i->v==fa|vis[i->v])    continue;
 65         dfs_dis(i->v,d+i->w,x);
 66     }
 67 }
 68
 69 inline ll calc(int x,int d){
 70     ll ret=0;
 71     num=0;
 72     dfs_dis(x,d,x);
 73     sort(dis,dis+num);
 74     int l=0,r=num-1;
 75     while(l<r){
 76         while(l<r&&dis[l]+dis[r]>K) r--;
 77         ret+=r-l;
 78         l++;
 79     }return ret;
 80 }
 81
 82 inline void solve(int u){
 83     top=inf;
 84     dfs_size(u,u);
 85     find_root(size[u],u,u);
 86     ans+=calc(root,0);
 87     vis[root]=true;
 88     for(edges *i=head[root];i;i=i->last)
 89         if(!vis[i->v]){
 90
 91             ans-=calc(i->v,i->w);
 92             solve(i->v);
 93         }
 94 }
 95
 96 int main(){
 97 #ifdef Troy
 98     while(scanf("%d%d",&n,&K)==2&&n&&K){
 99         clear();
100         for(int i=1,u,v,w;i<n;i++){
101             u=read(),v=read(),w=read();
102             push(u,v,w);
103         }
104         solve(1);
105         printf("%lld\n",ans);
106     }
107 #endif
108 }
109 /*
110 5 4
111 1 2 3
112 1 3 1
113 1 4 2
114 3 5 1
115 0 0
116 */
时间: 2024-10-10 21:36:06

【树的点分治——模板】的相关文章

【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树形dp/LCA/树的点分治

题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F1..F7表示, 每个农场最多能在东西南北四个方向连结4个不同的农场.此外,农场只处在道路的两端.道路不会交叉且每对农场间有且仅有一条路径.邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复了.每一条道路的信息如下: 从农场23往南经距离10到达农场17 从农场1往东经距离7到达农

树的直径、树的重心与树的点分治

树的直径 树的直径(Diameter)是指树上的最长简单路. 直径的求法:两遍搜索 (BFS or DFS) 任选一点w为起点,对树进行搜索,找出离w最远的点u. 以u为起点,再进行搜索,找出离u最远的点v.则u到v的路径长度即为树的直径. 简单证明: 如果w在直径上,那么u一定是直径的一个端点.反证:若u不是端点,则从直径另一端点到w再到u的距离比直径更长,与假设矛盾. 如果w不在直径上,且w到其距最远点u的路径与直径一定有一交点c,那么由上一个证明可知,u是直径的一个端点. 如果w到最远点u

hdu_5314_Happy King(树的点分治)

题目链接:hdu_5314_Happy King 题意: 给出一颗n个结点的树,点上有权值: 求点对(x,y)满足x!=y且x到y的路径上最大值与最小值的差<=D: 题解: 还是树的点分治,在统计答案的时候先按到根的最小值排序,然后用最大值减D去找有多少个满足答案. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 typedef pair<i

数据结构(树,点分治):POJ 1741 Tree

Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not e

bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 &amp;&amp; AC400

3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec  Memory Limit: 512 MBSubmit: 159  Solved: 40[Submit][Status][Discuss] Description 强 强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上是一个带权树.每个时刻它会长出一个新的叶子节点.每个节点上有一个可爱的小精灵,

bzoj 2152: 聪聪可可 树的点分治

2152: 聪聪可可 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 485  Solved: 251[Submit][Status] Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏.他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“

【bzoj3672】[Noi2014]购票 斜率优化+CDQ分治+树的点分治

题目描述 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费的最小代价(中途可以经停其它点) 输入 第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到).输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市.其中第 v 行包含 5 个非负整数 $f_v,s_v,p_v,q_v,l_v$,分别表示城市 v 的父亲城市,它到

【bzoj1316】树上的询问 树的点分治+STL-set

题目描述 一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. 输入 第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径. 输出 输出有p行,Yes或No. 样例输入 6 4 1 2 5 1 3 7 1 4 1 3 5 2 3 6 3 1 8 13 14 样例输出 Yes Yes No Yes

【bzoj4016】[FJOI2014]最短路径树问题 堆优化Dijkstra+DFS树+树的点分治

题目描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小.注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小).到达该点后按原路返回,然后往其他点走,直到所有点都走过. 可以知道,经过的边会构成一棵最短路径树.请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长