poj1987 Distance Statistics

普通dfs访问每个点对的复杂度是O(n^2)的,显然会超时。

考虑访问到当前子树的根节点时,统计所有经过根的点(u, v)满足:

dist(u) + dist(v) <= maxd,并且

belong(u)≠belong(v)(即u,v不在同一子树)。

这里说的距离指的是节点到跟的距离。

可以用作差法,即用所有满足条件的点对数减去那些在根节点为当前子树根节点的儿子节点的点对数。

上面一步可以用O(nlogn)的复杂度解决,即先排序再比较。

根节点子树可以递归解决,用树的点分治。

总复杂度上界是O(nlognlogn)。

http://poj.org/problem?id=1987

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 using namespace std;
  5 const int maxn = 1e5 + 10;
  6 const int inf = 0x3f3f3f3f;
  7 struct Edge{
  8     int to, next, w;
  9 }edge[maxn << 1];
 10 int head[maxn], N;
 11 int n, m, maxd;
 12 bool vis[maxn];
 13 int cnt[maxn];
 14 int maxi[maxn];
 15 int ans;
 16 int mini, root, sum;
 17 int buf[maxn], k;
 18
 19 void addEdge(int u, int v, int w){
 20     edge[N].next = head[u];
 21     edge[N].to = v;
 22     edge[N].w = w;
 23     head[u] = N++;
 24 }
 25
 26 void init(){
 27     N = 0;
 28     memset(head, -1, sizeof head);
 29 }
 30
 31 void get_cnt(int u){
 32     cnt[u] = 1;
 33     vis[u] = 1;
 34     maxi[u] = -1;
 35     buf[k++] = u;
 36     for(int i = head[u]; i + 1; i = edge[i].next){
 37         int v = edge[i].to;
 38         if(vis[v]) continue;
 39         get_cnt(v);
 40         cnt[u] += cnt[v];
 41         maxi[u] = max(maxi[u], cnt[v]);
 42     }
 43     vis[u] = 0;
 44 }
 45
 46 void get_dist(int u, int d){
 47     vis[u] = 1;
 48     buf[k++] = d;
 49     for(int i = head[u]; i + 1; i = edge[i].next){
 50         int v = edge[i].to;
 51         if(vis[v]) continue;
 52         get_dist(v, d + edge[i].w);
 53     }
 54     vis[u] = 0;
 55 }
 56
 57 int get_buf_sum(int left, int right){
 58     sort(buf + left, buf + right);
 59     int tem = 0;
 60     for(int i = right - 1, j = left; i >= left + 1; i--){
 61         while(j < i && buf[i] + buf[j] <= maxd) ++j;
 62         tem += min(i, j) - left;
 63     }
 64     return tem;
 65 }
 66
 67 void cal(int u){
 68     k = 0;
 69     get_cnt(u);
 70     mini = inf;
 71     for(int i = 0; i < k; i++){
 72         int tem = max(cnt[u] - cnt[buf[i]], maxi[buf[i]]);
 73         if(tem < mini) mini = tem, root = buf[i];
 74     }
 75     k = 0;
 76     vis[root] = 1;
 77     int tem = 0;
 78     for(int i = head[root]; i + 1; i = edge[i].next){
 79         int v = edge[i].to;
 80         if(vis[v]) continue;
 81         int pre = k;
 82         get_dist(v, edge[i].w);
 83         tem -= get_buf_sum(pre, k);
 84     }
 85     buf[k++] = 0;
 86     tem += get_buf_sum(0, k);
 87     ans += tem;
 88     for(int i = head[root]; i + 1; i = edge[i].next){
 89         int v = edge[i].to;
 90         if(vis[v]) continue;
 91         cal(v);
 92     }
 93 }
 94
 95 void solve(){
 96     scanf("%d", &maxd);
 97     memset(vis, 0, sizeof vis);
 98     ans = 0;
 99     for(int i = 1; i <= n; i++){
100         if(!vis[i]) cal(i);
101     }
102     printf("%d\n", ans);
103 }
104
105 int main(){
106     //freopen("in.txt", "r", stdin);
107     while(~scanf("%d", &n)){
108         scanf("%d", &m);
109         init();
110         for(int i = 0, x, y, z; i < m; i++){
111             scanf("%d%d%d", &x, &y, &z);
112             addEdge(x, y, z);
113             addEdge(y, x, z);
114             getchar(), getchar();
115         }
116         solve();
117     }
118     return 0;
119 }

时间: 2024-08-06 23:22:21

poj1987 Distance Statistics的相关文章

POJ1987——Distance Statistics

Distance Statistics Time Limit: 2000MS   Memory Limit: 64000K Total Submissions: 1667   Accepted: 532 Case Time Limit: 1000MS Description Frustrated at the number of distance queries required to find a reasonable route for his cow marathon, FJ decide

【点分治】poj1741 Tree / poj2114 Boatherds / poj1987 Distance Statistics

三道题都很类似.给出1741的代码 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define MAXN 10001 typedef pair<int,int> Point; int n,K,ans; int v[MAXN<<1],w[MAXN<<1],first[MAXN],next[MAXN<<1],en; vo

POJ 1987 Distance Statistics 树分治

Distance Statistics Description Frustrated at the number of distance queries required to find a reasonable route for his cow marathon, FJ decides to ask queries from which he can learn more information. Specifically, he supplies an integer K (1 <= K

【poj1987】 Distance Statistics

http://poj.org/problem?id=1987 (题目链接) 题意 给出一棵树,求树上距离不超过K的点对个数. Solution 点分治,同poj1741. 代码 // poj1987 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL

【POJ1987】Distance Statistics ==【POJ1741】 树分治

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44307489"); } 题意&题解 http://blog.csdn.net/vmurder/article/details/44302921 代码:(同一道题) #include <cstdio> #inclu

POJ 1987 Distance Statistics (树上点分治)

题目地址:POJ 1987 点分治模板题,跟POJ 1741几乎一样,.. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <stdi

bzoj 3365 [Usaco2004 Feb]Distance Statistics 路程统计(点分治,单调)

[题意] 求树上长度不超过k的点对数目. [思路] 和 Tree 一样一样的. 就是最后统计的时候别忘把根加上. [代码] 1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algori

POJ - 1987 Distance Statistics 树上的分治

题目大意:和poj 1741的那题和类似,求树上节点之间的距离小于等于k的节点对有多少对 解题思路:具体可参考:<分治算法在树的路径问题中的应用--漆子超> 给这题的输入坑了,注意输入,不然会超时 #include<cstdio> #include<vector> #include<algorithm> using namespace std; #define maxn 40010 int vis[maxn], Sum[maxn], d[maxn], dp[

POJ 1987 BZOJ 3365 Distance Statistics 树的分治(点分治)

题目大意:(同poj1741,刷一赠一系列) CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 40010 #define INF 0x3f3f3f3f using namespace std; int points,edges,k; int head[MAX],total; int next[MAX <<