美文网首页
POJ 1741 Tree

POJ 1741 Tree

作者: 苏子旃 | 来源:发表于2019-01-30 10:20 被阅读0次

    难度 尚未评定
    Description
    给定一颗有N个节点的树,每条边有一个权值。树上两个节点xy之间的路径长度就是路径上各条边的权值的合。
    求树上长度不超过K的路径有多少条。
    CCYOS
    这是一道点分治例题。

    1. 若指定p节点为根,则对于节点p,树上路径有两类:
      a. 经过根结点p
      b. 包含于p的某一子树,不经过p
    2. 对于第二类路径,可以视作每颗子树下的子问题递归处理。
      对于第一类路径(x,y),至多由两段组成:(x,p)(p,y)。求解第一类路径时,要记录d数组和rt数组,分别表示根结点到该点的距离和该点属于哪一棵子树。根据题意,\begin{cases} { rt[x] \not= rt[y]}\\ \ d[x] + d[y] \leq K \end{cases}
    3. 构建clac(p)函数,统计在以p为根的树中满足上述要求的点对个数。
    4. 实现方法:
      一 · 树上直接统计
      对于根结点p下的子树为s_1,s_2,s_3……,s_m
      对于s_i中的每个节点x,将在子树s_1,s_2,……,s_i - 1中满足d[x] + d[y] \leq k的节点y数量加入答案中即可。
      可建立树状数组求解。
      本做法应用:YALI 0J 2902B 文学
      二·指针扫描数组
      把树上每个点放入数组a,并将数组按照d值排序。
      使用两个指针L,R从前后扫描数组a
      不难发现在L向右扫描的过程中,R的范围是从右往左单调递减的。(不能加大数了)
      另外处理一个数组cnt[s],维护在(L,R]之间满足rt[a[i]] = s的位置i的个数。
      则易得当x == a[L]时,答案即为R - L - cnt[rt[a[L]]]
      本做法应用:POJ 1741 Tree
    5. 总结点分治算法过程:
      a.找到树的中心p作为根结点。
      b.从p进行dfs,求出rtd数组。
      c.clac(p)统计答案。
      d.删除根结点p,对p的每颗子树进行a - d。

    code

    #include<cstdio> 
    #include<iostream>
    #include<cmath>  
    #include<algorithm>  
    using  namespace std;  
    struct EDGE{  int to,next;  long  long w;  }edg[80005];  
    int n,tot,root,limit,siz,vis[40005],head[40005],size[40005];  
    long  long k,ans,l,r;  
    long que[40005],dis[40004];  
    inline  void adde(int x,int y,int w){ edg[++tot].to = y; edg[tot].w = w; edg[tot].next  = head[x]; head[x]  = tot;  } 
    inline  void getroot(int p,int fa){
      size[p]  =  1;  int num =  0;//从p点出发的子树大小 
      for(int i = head[p];i;i = edg[i].next){
        int to = edg[i].to;  
        if(fa == to||vis[to])continue; 
        getroot(to,p); size[p]  += size[to]; 
        num = max(num,size[to]);  
      } 
      num = max(num,siz - size[p]);  
      if(num < limit){//limit:当前最小 
        limit = num; root = p;  
      }  
    }  
    inline  void getdis(int p,int fa){ 
      que[++r]  = dis[p];    
      for(int i = head[p];i;i = edg[i].next){
        int to = edg[i].to;
        if(to == fa||vis[to])continue;
        dis[to]  = dis[p]  + edg[i].w; getdis(to,p);  
      }  
    }  
    inline  long  long clac(int p,int v){
      r =  0; dis[p]  = v;  
      long  long sum =  0; 
      getdis(p,0); 
      l =  1; 
      sort(que +  1,que + r +  1);  
      while(l < r){
        if(que[l]  + que[r]  <= k)sum += r - l,++l;  
        else r--;  
      }  
      return sum;  
    }  
    inline  void dfs(int p){
      ans += clac(p,0); vis[p]  =  1;//将p点作为根结点是否处理完毕
      for(int i = head[p];i;i = edg[i].next){
        int to = edg[i].to;
        if(vis[to])continue;
        ans -= clac(to,edg[i].w);
        siz = size[to];
        limit =  2147483647;
        getroot(to,0);
        dfs(root);  
      }  
    }  
    inline  void init(){ 
      tot =  0;ans =  0;  
      for(int i =  1;i <= n;++i)head[i]  =  0,vis[i]  =  0;  
    }  
    int main(){ 
      scanf("%d%lld",&n,&k);  
      int x,y;  long  long w;  
      while(n&&k){  for(int i =  1;i < n;++i){   
        scanf("%d%d%lld",&x,&y,&w); 
        adde(x,y,w); adde(y,x,w);  
      } 
      limit =  2147483647;// 
      siz = n;//对于第一棵子树的大小限制     
      getroot(1,0);//找到树的重心,更新root 
      dfs(root);//从root开始递归统计更新答案 
      printf("%lld\n",ans); init(); 
      scanf("%d%lld",&n,&k);  
      }  
    return  0;  
    }
    

    相关文章

      网友评论

          本文标题:POJ 1741 Tree

          本文链接:https://www.haomeiwen.com/subject/fykajqtx.html