标签: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
解题代码:
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 }
标签:style blog http color io os ar for strong
原文地址:http://www.cnblogs.com/zyue/p/4007279.html