zoukankan      html  css  js  c++  java
  • 【POJ 1741】 Tree (树的点分治)

    Tree
     

    Description

    Give a tree with n vertices,each edge has a length(positive integer less than 1001). 
    Define dist(u,v)=The min distance between node u and v. 
    Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. 
    Write a program that will count how many pairs which are valid for a given tree. 

    Input

    The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l. 
    The last test case is followed by two zeros. 

    Output

    For each test case output the answer on a single line.

    Sample Input

    5 4
    1 2 3
    1 3 1
    1 4 2
    3 5 1
    0 0
    

    Sample Output

    8

    Source

     
     
    【题意】
      求树上两点间距离小等于K的方案数 (n<=10000)
     
    【分析】
      经典的点分治问题。
      搞笑的我知道怎么做都纠集好久,纠结症怎么破。
      每层求重心方法分治是nlogn的。
      具体是,每次都只算lca为根的点对。
      设dis[x]为x节点到根的距离,那么我们求dis[x]+dis[y]<=k的方案数,并且x和y要在同子树上。
      先不考虑在不同子树上,直接求dis[x]+dis[y]<=k可以排序一次然后for一遍动态累加,然后再把同一棵子树上的方案数剪掉。
     
    代码如下:
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<cmath>
      8 using namespace std;
      9 #define Maxn 10010
     10 #define INF 0xfffffff
     11 
     12 struct node
     13 {
     14     int x,y,c,next;
     15 }t[Maxn*2];int len;
     16 int first[Maxn];
     17 int n,k;
     18 
     19 int mymax(int x,int y) {return x>y?x:y;}
     20 
     21 void ins(int x,int y,int c)
     22 {
     23     t[++len].x=x;t[len].y=y;t[len].c=c;
     24     t[len].next=first[x];first[x]=len;
     25 }
     26 int rt;
     27 bool q[Maxn];
     28 int sm[Maxn],mx[Maxn],dep[Maxn];
     29 int v[Maxn],vl;
     30 
     31 void dfs(int x,int h,int f)
     32 {
     33     mx[x]=-1;sm[x]=1;
     34     for(int i=first[x];i;i=t[i].next) if(t[i].y!=f&&q[t[i].y])
     35     {
     36         int y=t[i].y;//dep[y]=dep[x]+t[i].c;
     37         dfs(y,h,x);
     38         sm[x]+=sm[y];
     39         mx[x]=mymax(mx[x],sm[y]);
     40     }
     41     mx[x]=mymax(mx[x],h-sm[x]);
     42     if(mx[x]<mx[rt]) rt=x;
     43 }
     44 
     45 int get_ans()
     46 {
     47     int now=1,ans=0;
     48     sort(v+1,v+1+vl);
     49     for(int i=vl;i>=1;i--)
     50     {
     51         if(now>i) now=i;
     52         while(v[i]+v[now]<=k&&now<i) now++;
     53         ans+=now-1;
     54     }
     55     return ans;
     56 }
     57 
     58 void dfs2(int x,int f)
     59 {
     60     v[++vl]=dep[x];
     61     for(int i=first[x];i;i=t[i].next) if(t[i].y!=f&&q[t[i].y])
     62     {
     63         int y=t[i].y;
     64         dep[y]=dep[x]+t[i].c;
     65         dfs2(y,x);
     66     }
     67 }
     68 
     69 int fans;
     70 
     71 void ffind(int x,int f)
     72 {
     73     vl=0;dep[x]=0;dfs2(x,0);
     74     fans+=get_ans();
     75     q[x]=0;
     76     for(int i=first[x];i;i=t[i].next) if(t[i].y!=f&&q[t[i].y])
     77     {
     78         int y=t[i].y;
     79         vl=0;dfs2(y,x);
     80         fans-=get_ans();
     81     }int i;
     82     for(i=first[x];i;i=t[i].next) 
     83         if(t[i].y!=f&&q[t[i].y])
     84     {
     85         rt=0;
     86         dfs(t[i].y,x,sm[t[i].y]);
     87         ffind(rt,x);
     88     }
     89 }
     90 
     91 int main()
     92 {
     93     while(1)
     94     {
     95         scanf("%d%d",&n,&k);
     96         if(n==0&&k==0) break;
     97         memset(first,0,sizeof(first));
     98         len=0;
     99         for(int i=1;i<n;i++)
    100         {
    101             int x,y,c;
    102             scanf("%d%d%d",&x,&y,&c);
    103             ins(x,y,c);ins(y,x,c);
    104         }
    105         fans=0;
    106         memset(q,1,sizeof(q));
    107         mx[0]=INF;
    108         rt=0;vl=0;dfs(1,n,0);
    109         ffind(rt,0);
    110         printf("%d
    ",fans);
    111     }
    112     return 0;
    113 }
    [POJ 1741]

    其实不知道我打的点分治标不标准,感觉很丑。这题就有3个dfs,ffind是求分治的子树答案,dfs是求子树重心,dfs2是求dis以及把子树的dis加入到v中排序。

    2016-10-16 22:16:44

  • 相关阅读:
    ASP内置对象
    VBscript脚本语言
    2018校园招聘求职记
    0.3W微功率放大器
    画一画BeagleboneBlack的PCB
    硬件类实习面试经历(已跪)
    2017会是改变人生轨迹的一年
    windows下使用vs code调试简单的C程序
    Beagleboneblack的MLO文件干了些啥
    模仿u-boot的makefile结构
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5967953.html
Copyright © 2011-2022 走看看