• POJ 1741 Tree 树分治(点分治)


    题意:给你一颗带边权树,问你其中 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
    ",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**
    ",k);
    112     root = k ; 
    113     getsize(k,0);
    114     mxv = 1e9;
    115     getroot(k,0,sum[k]);
    116     k = root;
    117     //printf("%d %d
    ",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
    ",tans,j,dn);
    131         }
    132     }
    133     int ans = getans(0,dn) - tans;
    134 /*    printf("ans = %d
    ",ans);
    135     for(int i = 0 ;i < dn ;i++)
    136         printf("%d ",dis[i]);
    137     printf("
    ");
    138     printf("ans = %d
    ",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
    ",solve(1));
    168     }
    169     return 0;
    170 }
    View Code
    没有梦想,何谈远方
  • 相关阅读:
    TOMCAT原理详解及请求过程
    详解Tomcat配置及使用
    Android网络编程(三)Volley使用方法全解析
    Android开发文档翻译之-Services
    竞赛中经常使用的C++写法
    Android消息机制
    boost的内存管理
    二叉树遍历技巧
    【 D3.js 视频系列 】 飞速入门
    [Spring实战系列](19)Servlet不同版本号之间的差别
  • 原文地址:https://www.cnblogs.com/zyue/p/4007279.html
Copyright © 2020-2023  润新知