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 }
View Code

 

posted @ 2015-10-15 13:41  astoninfer  阅读(207)  评论(0编辑  收藏  举报