POJ 1741 男人八題——樹分治
阿新 • • 發佈:2017-08-26
tor pst def roo 容易 air sizeof ram 出發 Tree
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 exceed k.
Write a program that will count how many pairs which are valid for a given tree.
The last test case is followed by two zeros.
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 23829 | Accepted: 7900 |
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 exceed k.
Input
The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.Output
For each test case output the answer on a single line.Sample Input
5 4 1 2 3 1 3 1 1 4 2 3 5 1 0 0
Sample Output
8
Source
[email protected] 樹分治: 分治很清楚是指分而治之,樹就分成了子樹,但是怎麽分才能是的分才最適合呢? 就像快速排序一樣,也有可能退化,於是,用樹的重心,這個DP很容易,但是,要每棵子樹都要求重心呢? 以某一棵子樹為研究對象,有多少個點對滿足 d[i] + d[j] <= k 呢? 對這個子樹 dfs求出 d ,距離 “根” 的距離(這個根是變化的); 將所有 d排序,掃描即可。 從根出發,遞歸到子節點,子節點再求,這樣子節點求得的會有一部分重合。減去經過父親結點的那些 <= k 的點對(此時,就是求以子節點為根,系數相差 d[f][v] 的 點對)。 至此,這個關於 點的 樹分治,就解決了!!! 男人八題寫了3題了。#include <cstdio> #include<cstring> #include <algorithm> #include <vector> using namespace std; #define N 10005 struct Node { int v,l; }; vector<Node> g[N]; int n,k; int s[N],f[N]; bool done[N]; int size; int root; void getroot(int u,int fa) { s[u] = 1; f[u] = 0; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(v!=fa&&!done[v]) { getroot(v,u); s[u] +=s[v]; f[u] = max(f[u],s[v]); } } f[u] = max(f[u],size-s[u]); if(f[u]<f[root]) root = u; } vector<int> dep; int d[N]; void getdep(int u,int fa) { dep.push_back(d[u]); s[u] = 1; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(v!=fa&&!done[v]) { d[v] = d[u] + g[u][i].l; getdep(v,u); s[u]+=s[v]; } } } int calc(int u,int init) { dep.clear(); d[u] = init; getdep(u,0); sort(dep.begin(),dep.end()); int ret = 0; for(int l=0,r=dep.size()-1;l<r;) if(dep[l]+dep[r]<=k) ret += r-l++; else r--; return ret; } int ans; void work(int u) { ans+=calc(u,0); done[u] = true; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(!done[v]) { ans-=calc(v,g[u][i].l); f[0] = size = s[v]; getroot(v,root=0); work(root); } } } int main() { while(scanf("%d%d",&n,&k),n) { for(int i=0; i <= n; i++) g[i].clear(); memset(done,0,sizeof(done)); int u,v,l; for(int i=1; i < n; i++) { scanf("%d%d%d",&u,&v,&l); g[u].push_back((Node){v,l}); g[v].push_back((Node){u,l}); } f[0] = size = n; getroot(1,root=0); ans = 0; work(root); printf("%d\n",ans); } return 0; }
POJ 1741 男人八題——樹分治