【POJ1741】Tree(点分治)

题意:

思路:点分治论文题

我们知道一条路径要么过根结点,要么在一棵子树中,这启发了我们可以使用分治算法。

记 Depth(i)表示点i 到根结点的路径长度, Belong(i) = X ( X 为根结点的某个儿子,且结点i 在以 X 为根的子树内)。

那么我们要统计的就是:

满足 Depth (i) + Depth ( j)<= K 且 Belong(i) <>Belong(j) 的 (i, j) 个数

= 满足 Depth(i) +Depth( j) <= K 的 (i, j) 个数

– 满足 Depth(i) + Depth( j) <= K 且 Belong(i) =Belong( j)的 (i, j) 个数

而对于这两个部分,都是要求出满足 Ai+Aj <= k 的(i, j) 的对数。

将 A 排序后利用单调性我们很容易得出一个O(N) 的算法,所以我们

可以用O(N log N)的时间来解决这个问题。

综上,此题使用树的分治算法时间复杂度为O(N log^2 N) 。

  1 var head,vet,next,len,son,flag,d:array[1..50000]of longint;
  2     dep,f:array[0..50000]of longint;
  3     n,m,i,x,y,z,tot,ans,sum,root,k:longint;
  4
  5 procedure swap(var x,y:longint);
  6 var t:longint;
  7 begin
  8  t:=x; x:=y; y:=t;
  9 end;
 10
 11 procedure add(a,b,c:longint);
 12 begin
 13  inc(tot);
 14  next[tot]:=head[a];
 15  vet[tot]:=b;
 16  len[tot]:=c;
 17  head[a]:=tot;
 18 end;
 19
 20 function max(x,y:longint):longint;
 21 begin
 22  if x>y then exit(x);
 23  exit(y);
 24 end;
 25
 26 procedure getroot(u,fa:longint);
 27 var e,v:longint;
 28 begin
 29  son[u]:=1; f[u]:=0;
 30  e:=head[u];
 31  while e<>0 do
 32  begin
 33   v:=vet[e];
 34   if (v<>fa)and(flag[v]=0) then
 35   begin
 36    getroot(v,u);
 37    son[u]:=son[u]+son[v];
 38    f[u]:=max(f[u],son[v]);
 39   end;
 40   e:=next[e];
 41  end;
 42  f[u]:=max(f[u],sum-f[u]);
 43  if f[u]<f[root] then root:=u;
 44 end;
 45
 46 procedure getdeep(u,fa:longint);
 47 var e,v:longint;
 48 begin
 49  inc(dep[0]); dep[dep[0]]:=d[u];
 50  e:=head[u];
 51  while e<>0 do
 52  begin
 53   v:=vet[e];
 54   if (v<>fa)and(flag[v]=0) then
 55   begin
 56    d[v]:=d[u]+len[e];
 57    getdeep(v,u);
 58   end;
 59   e:=next[e];
 60  end;
 61 end;
 62
 63 procedure qsort(l,r:longint);
 64 var i,j,mid:longint;
 65 begin
 66  i:=l; j:=r; mid:=dep[(l+r)>>1];
 67  repeat
 68   while mid>dep[i] do inc(i);
 69   while mid<dep[j] do dec(j);
 70   if i<=j then
 71   begin
 72    swap(dep[i],dep[j]);
 73    inc(i); dec(j);
 74   end;
 75  until i>j;
 76  if l<j then qsort(l,j);
 77  if i<r then qsort(i,r);
 78 end;
 79
 80 function clac(u,now:longint):longint;
 81 var l,r:longint;
 82 begin
 83  d[u]:=now; dep[0]:=0;
 84  getdeep(u,0);
 85  qsort(1,dep[0]);
 86  clac:=0;
 87  l:=1; r:=dep[0];
 88  while l<r do
 89  begin
 90   if dep[l]+dep[r]<=k then begin clac:=clac+r-l; inc(l); end
 91    else dec(r);
 92  end;
 93 end;
 94
 95 procedure work(u:longint);
 96 var e,v:longint;
 97 begin
 98  ans:=ans+clac(u,0);
 99  flag[u]:=1;
100  e:=head[u];
101  while e<>0 do
102  begin
103   v:=vet[e];
104   if flag[v]=0 then
105   begin
106    ans:=ans-clac(v,len[e]);
107    sum:=son[v];
108    root:=0;
109    getroot(v,root);
110    work(root);
111   end;
112   e:=next[e];
113  end;
114 end;
115
116 begin
117  assign(input,‘poj1741.in‘); reset(input);
118  assign(output,‘poj1741.out‘); rewrite(output);
119  while not eof do
120  begin
121   fillchar(head,sizeof(head),0);
122   fillchar(flag,sizeof(flag),0);
123   tot:=0;
124   readln(n,k);
125   if (n=0)and(m=0) then break;
126   for i:=1 to n-1 do
127   begin
128    readln(x,y,z);
129    add(x,y,z);
130    add(y,x,z);
131   end;
132   sum:=n; f[0]:=maxlongint; ans:=0;
133   getroot(1,0);
134   work(root);
135   writeln(ans);
136  end;
137  close(input);
138  close(output);
139 end.
时间: 2024-12-25 02:51:17

【POJ1741】Tree(点分治)的相关文章

POJ1741:Tree——点分治

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

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

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

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

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

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

[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) :

树分治基础模板以及树的重心(poj1741 tree)

好久没有更新博文了,这里更新一发~~ 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

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

poj1741 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

[poj1741 Tree]树上点分治

题意:给一个N个节点的带权树,求长度小于等于K的路径条数 思路:选取一个点作为根root,假设f(root)是当前树的答案,那么答案来源于两部分: (1)路径不经过root,那么就是完全在子树内,这部分可以递归统计 (2)路径经过root,这部分可以通过容斥原理统计,具体见有关点分治资料... 点分治有个特点,当考虑的问题由根这个子树转为儿子的子树时,可以选取任意点作为新的根,只要它在儿子的子树内,这就使得我们可以通过选取特别的点使得树深度更小,这个点就是树的重心(在程序里面是不断找子树的重心)

POJ1741 Tree(树分治)

题意: 求树上距离小于等于K的点对有多少个 思路: 每次分治,我们首先算出重心,为了计算重心,需要进行两次dfs,第一次把以每个结点为根的子树大小求出来,第二次是从这些结点中找重心 找到重心后,需要统计所有结点到重心的距离,看其中有多少对小于等于K 但是这些求出来满足小于等于K的里面只有那些路径经过重心的点对才是有效的,也就是说在同一颗子树上的肯定不算数的,所以对每颗子树,把子树内部的满足条件的点对减去. /* ******************************************