男人八题_POJ-1741

题目链接:http://poj.org/problem?id=1741

树分治相关论文:http://wenku.baidu.com/view/60c6aa1ffc4ffe473368aba8.html

由于论文中有该题的讲解,所以便不再赘述。代码如下

  1 #include<cstdio>

  2 #include<cstdlib>

  3 #include<cstring>

  4 #include<algorithm>

  5 using namespace std;

  6 #define lowbit(a) ((a)&(-a))

  7 #define max(a, b) ((a)>(b)?(a):(b))

  8 #define min(a, b) ((a)<(b)?(a):(b))

  9 #define MAXN 10010

 10 #define MAXM 20010

 11 #define PI 3.1415926

 12 #define E 2.718281828

 13 #define INF 0x777777f

 14 typedef long long LL;

 15 

 16 int eCnt, fir[MAXN]; struct edge{int v, w, nxt;} eg[MAXM];

 17 int n, k, ans, q[MAXN], size[MAXN], maxx[MAXN], vis[MAXN], dis[MAXN];

 18 

 19 void addedge(int u, int v, int w){

 20     eg[++eCnt].v = v; eg[eCnt].w = w;

 21     eg[eCnt].nxt = fir[u]; fir[u] = eCnt;

 22 }

 23 void init(){

 24     eCnt = ans = 0;

 25     for (int i = 0; i <= n; i++){

 26         vis[i] = fir[i] = 0;

 27     }

 28 }

 29 /*找出树的重心*/

 30 int bfs_root(int u){

 31     int h = 1, t = 1, ret = 0; maxx[0] = INF;

 32     q[t] = u; maxx[u] = 0; size[u] = 1; vis[u] = 2;

 33     for ( ; h <= t; h++){

 34         for (int u = q[h], e = fir[u]; e != 0; e = eg[e].nxt){

 35             if (!vis[eg[e].v]){

 36                 vis[eg[e].v] = 2;

 37                 q[++t] = eg[e].v;

 38                 size[eg[e].v] = 1;

 39                 maxx[eg[e].v] = 0;

 40             }

 41         }

 42     }

 43     for (h--; h > 0; h--){

 44         int u = q[h];

 45         vis[u] = 0;

 46         for (int e = fir[u]; e != 0; e = eg[e].nxt){

 47             if (!vis[eg[e].v]){

 48                 size[u] += size[eg[e].v];

 49                 maxx[u] = max(maxx[u], size[eg[e].v]);

 50             }

 51         }

 52         maxx[u] = max(t-size[u], maxx[u]);

 53         if (maxx[u] < maxx[ret]) ret = u;

 54     }

 55     return ret;

 56 }

 57 /*预处理root到子节点的距离*/

 58 int dfs_dis(int u){

 59     int h = 1, t = 1;

 60     q[t] = u; dis[t] = 0; vis[u] = 2;

 61     for ( ; h <= t; h++){

 62         for (int u = q[h], e = fir[u]; e != 0; e = eg[e].nxt){

 63             if (!vis[eg[e].v]){

 64                 vis[eg[e].v] = 2;

 65                 q[++t] = eg[e].v;

 66                 dis[t] = dis[h] + eg[e].w;

 67             }

 68         }

 69     }

 70     for (h = 1; h <= t; h++) vis[q[h]] = 0;

 71     return t;

 72 }

 73 /*计算满足长度小于k且经过u的路径的数量,且路径可以不合法*/

 74 int dfs_calc(int u, int k){

 75     int num = dfs_dis(u), ret = 0;

 76     sort(dis+1, dis+1+num);

 77     for (int i = 1, j = num; i < j; i++){

 78         for ( ; dis[i] + dis[j] > k; j--)

 79             if (i == j) break;

 80         ret += j - i;

 81     }

 82     return ret;

 83 }

 84 /*点分治*/

 85 void dfs(int u){

 86     int root = bfs_root(u);

 87     ans += dfs_calc(root, k);

 88     vis[root] = 1;

 89     for (int e = fir[root]; e != 0; e = eg[e].nxt){

 90         int v = eg[e].v;

 91         if (vis[v]) continue;

 92         ans -= dfs_calc(v, k-eg[e].w*2);

 93         dfs(v);

 94     }

 95 }

 96 int main(){

 97     int u, v, w;

 98     for ( ; ; ){

 99         init();

100         scanf("%d%d", &n, &k);

101         if (n == 0 && k == 0) break;

102         for (int i = 1; i < n; i++){

103             scanf("%d%d%d", &u, &v, &w);

104             addedge(u, v, w);

105             addedge(v, u, w);

106         }

107         dfs(1);

108         printf("%d\n", ans);

109     }

110     return 0;

111 }

 

你可能感兴趣的:(poj)