码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 1741 Tree 树分治(点分治)

时间:2014-10-05 21:05:48      阅读:221      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   ar   for   strong   

题意:给你一颗带边权树,问你其中 dis(v,u) <= k 的对数

解题思路:

首先推荐大家看 09年国家集训队漆子超 的论文   

 

看到这题  我们可以有三种思路 

第一种是枚举起点,遍历整颗树找对数    时间复杂度 为  O(n^2),空间复杂度为 O(n)

第二种是树形dp的思想     每个节点用 长度为 K 数组维护 ,递归求解  时间复杂度为 O(n ^k)空间复杂度 为 O(n)

第三种就是我们要用到的点分治的思想。

这种思想的具体思路是  先找到一个  根  对这个根进行 深搜, 找出 根到 其所有子节点的距离D[I]

分两种情况,第一种是 点对不经过 这个 根 ,那么递归子节点就行

第二种情况就是 点经过这个根 ,这里又分两种情况

那么其中 D[i] + D[j] <= K  为我们所求

但是   D[i] + D[j] <= K 的情况中  有可能 i 和 j 是属于 根的同一颗子树的,所以要去除掉这种情况,

可以知道 这两种情况可以调用一个函数计数,具体的方法就是 对 D[i] 排序 ,首尾双递推。 这里时间复杂度为 N×logn(对与第二种,我们可以用全局数组,每次处理一个子节点的一段) 

找完这个根以后我们需要  删除  这个 根  ,继续 寻找子树就行。对与每一颗子树,我们要使得时间复杂度尽可能低的话,我们需要找到这颗子数的重心为根。

那这样递归层数就变成了  logn   总时间复杂度为  N×lognxlogn

解题代码:

bubuko.com,布布扣
  1 // File Name: poj1741.cpp
  2 // Author: darkdream
  3 // Created Time: 2014年10月05日 星期日 09时49分58秒
  4 
  5 #include<vector>
  6 #include<list>
  7 #include<map>
  8 #include<set>
  9 #include<deque>
 10 #include<stack>
 11 #include<bitset>
 12 #include<algorithm>
 13 #include<functional>
 14 #include<numeric>
 15 #include<utility>
 16 #include<sstream>
 17 #include<iostream>
 18 #include<iomanip>
 19 #include<cstdio>
 20 #include<cmath>
 21 #include<cstdlib>
 22 #include<cstring>
 23 #include<ctime>
 24 #define LL long long
 25 #define maxn 10005
 26 using namespace std;
 27 int n , m ; 
 28 struct node{
 29     int ne;
 30     int dis; 
 31     node(int _ne,int _dis)
 32     {
 33         ne = _ne;
 34         dis = _dis;
 35     }
 36 };
 37 vector<node> mp[maxn];
 38 int dn = 0; 
 39 int vis[maxn];
 40 int dis[maxn];
 41 int sum[maxn];
 42 int mx[maxn];
 43 
 44 int getsize(int k , int la)
 45 {
 46     sum[k] = 1;
 47     mx[k] = 0;
 48     int num = mp[k].size();
 49     for(int i = 0;i < num ;i ++)
 50     {
 51         if(!vis[mp[k][i].ne] && mp[k][i].ne != la)
 52         {
 53             getsize(mp[k][i].ne,k);
 54             mx[k] = max(sum[mp[k][i].ne],mx[k]);
 55             sum[k] += sum[mp[k][i].ne];
 56         }
 57     }
 58 }
 59 int root;
 60 int mxv;
 61 void getroot(int k ,int la,int tans)
 62 {
 63     int tt = max(tans - sum[k] ,mx[k]);
 64     if(tt <  mxv)
 65     {
 66     //   printf("****%d\n",k);
 67         mxv = tt; 
 68         root = k ; 
 69     }
 70     int num = mp[k].size();
 71     for(int i = 0 ;i < num ;i ++)
 72     {
 73         if(!vis[mp[k][i].ne] && mp[k][i].ne != la)
 74         {
 75             getroot(mp[k][i].ne,k,tans);
 76         }
 77     }
 78 }
 79 void getdis(int k , int la,int tdis)
 80 {
 81     dis[dn] = tdis;
 82     dn ++ ;
 83     int num = mp[k].size();
 84     for(int i = 0 ;i < num ;i ++)
 85     {
 86         if(mp[k][i].ne != la && !vis[mp[k][i].ne]) 
 87         {
 88             getdis(mp[k][i].ne,k,tdis + mp[k][i].dis);
 89         }
 90     }
 91 }
 92 int getans(int l ,int r )
 93 {
 94     sort(dis+l,dis+r);
 95     int ans = 0 ; 
 96     r = r-1;
 97     while(r > l)
 98     {
 99         if(dis[l] + dis[r] <= m)
100         {
101             ans += r - l ; 
102             l ++ ;
103         }else {
104             r-- ;
105         }
106     }
107     return ans;
108 }
109 int solve(int k)
110 {
111 //    printf("%d**\n",k);
112     root = k ; 
113     getsize(k,0);
114     mxv = 1e9;
115     getroot(k,0,sum[k]);
116     k = root;
117     //printf("%d %d\n",k,sum[k]);
118     dn = 1 ; 
119     dis[0] = 0;
120     int tans = 0 ; 
121     int j ;
122     int num = mp[k].size();
123     for(int i = 0 ;i < num ;i ++)
124     {
125         if(!vis[mp[k][i].ne])
126         {
127             j = dn;
128             getdis(mp[k][i].ne,k,mp[k][i].dis);
129             tans += getans(j,dn);
130     //        printf("%d %d %d\n",tans,j,dn);
131         }
132     }
133     int ans = getans(0,dn) - tans;
134 /*    printf("ans = %d\n",ans);
135     for(int i = 0 ;i < dn ;i++)
136         printf("%d ",dis[i]);
137     printf("\n");
138     printf("ans = %d\n",ans);
139 */
140     vis[k] = 1;  //删除这个点
141 
142     for(int i = 0 ;i < num ;i ++)
143     {
144         if(!vis[mp[k][i].ne])
145         {
146             ans += solve(mp[k][i].ne);
147         }
148     }
149     return ans;
150 }
151 int main(){
152     //freopen("out","r",stdin);
153     while(scanf("%d %d",&n,&m) != EOF)
154     {
155         if(n == 0 && m == 0 )
156             break;
157         int u,v,w;
158         for(int i = 1;i <= n;i ++)
159             mp[i].clear();
160         for(int i = 1;i < n;i ++)
161         {
162             scanf("%d %d %d",&u,&v,&w);
163             mp[u].push_back(node(v,w));
164             mp[v].push_back(node(u,w));
165         }
166         memset(vis,0,sizeof(vis));
167         printf("%d\n",solve(1));
168     }
169     return 0;
170 }
View Code

 

POJ 1741 Tree 树分治(点分治)

标签:style   blog   http   color   io   os   ar   for   strong   

原文地址:http://www.cnblogs.com/zyue/p/4007279.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!