• poj1741 树上的点分治


    题意:

    一棵10000个点的树,每条边的长不超过1000,给定一个值k,问距离不超过k的点对数有多少。(多组数据)

    输入样例:

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

    输出样例:
    8

    ————————————————————————————————————————————————————————————————————————————
    这个题目是在CODEVS 2756 树上的路径 的学习过程中看到别人的题解的过程中看到的,这个题相对简单,是做那个题的基础。基本上是人家的代码,和抄也差不了多少。是学习树上的点分治的一个基础题。
    根据一个大神漆子超的论文,树上的分治可以分为点分治,边分治和链分治。点分治最差log,边分治最差n。而链分治是最好的,不过没有学会,有空再从网上找来学习一下,就是只学习点皮毛,对自己做题思路也是一种扩展。
    点分治,就是在树中去掉一个点,从而使原来的树变成更小的树,从而达到分治的目的。为了防止极差情况的出现,提高分治的效率,最好的分治点是树的重心(去掉该点后,所得最大子树最小)。所在就有了点分治的方法。
    1、深搜,得到各个点为根的子树的大小和各个点的最大子树的大小
    2、二次深搜,得到去掉各个点得到的最大子树的大小,从而通过遍历得到重心。
    3、应用问题与重心的关系进行分治。
    (本题中:
    3.1、计算通过重心且不超过k的点对数(包含重边)。
    3.2、减去过重心且不超过k的点对数(即有重边的点对数)。
    3.3、标明已查到的重心(vis),在新生成的子树中重新进行上述操作,完成分治。


    边分治,没有做过,不过据漆子超说,是去掉一条过,把树分成2个树,完成分治。个人愚见,如果不是星型那种极个别的情况也可以实现log。
    ————————————————————————————————————————————————————————————————————————————
      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<algorithm>
      5 
      6 using namespace std;
      7 const int maxn=10010;
      8 
      9 int n,k,ans;
     10 struct edge
     11 {
     12     int u,v,w,next;
     13 }e[2*maxn];
     14 int head[maxn],js,jst,mi,root;
     15 int siz[maxn],mx[maxn],dis[maxn];
     16 bool vis[maxn];
     17 void init()
     18 {
     19     memset(head,0,sizeof(head));
     20     memset(vis,0,sizeof(vis));
     21     js=0;
     22     ans=0;
     23 }
     24 void readint(int &x)
     25 {
     26     int f=1;
     27     char c=getchar();
     28     for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-f;
     29     x=0;
     30     for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
     31     x=x*f;
     32 }
     33 void addage(int u,int v,int w)
     34 {
     35     e[++js].u=u;e[js].v=v;e[js].w=w;
     36     e[js].next=head[u];head[u]=js;
     37 }
     38 void dfssize(int u,int fa)
     39 {
     40     siz[u]=1;mx[u]=0;
     41     for(int i=head[u];i;i=e[i].next)
     42     {
     43         int v=e[i].v;
     44         if(v!=fa && !vis[v])
     45         {
     46             dfssize(v,u);
     47             siz[u]+=siz[v];
     48             if(siz[v]>mx[u])mx[u]=siz[v];
     49         }
     50     }
     51 }
     52 void dfsroot(int r,int u,int f)
     53 {
     54     if(siz[r]-siz[u]>mx[u])mx[u]=siz[r]-siz[u];
     55     if(mx[u]<mi)
     56     {
     57         mi=mx[u];
     58         root=u;
     59     }
     60     for(int i=head[u];i;i=e[i].next)
     61     {
     62         int v=e[i].v;
     63         if(v!=f &&!vis[v])
     64         {
     65             dfsroot(r,v,u);
     66         }
     67     }
     68 }
     69 void dfsdis(int u,int d,int f)
     70 {
     71     dis[jst++]=d;
     72     for(int i=head[u];i;i=e[i].next)
     73     {
     74         int v=e[i].v;
     75         if(v!=f && !vis[v])
     76         dfsdis(v,d+e[i].w,u);
     77     }
     78 }
     79 int calc(int u,int d)
     80 {
     81     int anst=0;
     82     jst=0;
     83     dfsdis(u,d,0);
     84     sort(dis,dis+jst);
     85     int i=0,j=jst-1;
     86     while(i<j)
     87     {
     88         while(dis[i]+dis[j]>k && i<j)j--;
     89         anst+=j-i;
     90         i++;
     91     }
     92     return anst;
     93 }
     94 void dfs(int u)
     95 {
     96     mi=n;
     97     dfssize(u,0);
     98     dfsroot(u,u,0);
     99     ans+=calc(root,0);
    100     vis[root]=1;
    101     for(int i=head[root];i;i=e[i].next)
    102     {
    103         int v=e[i].v;
    104         if(!vis[v])
    105         {
    106             ans-=calc(v,e[i].w);
    107             dfs(v);
    108         }
    109         
    110     }
    111     
    112 }
    113 int main()
    114 {
    115     while(scanf("%d%d",&n,&k)==2)
    116     {
    117         if(!n && !k)break;
    118         init();
    119         for(int u,v,w,i=1;i<n;i++)
    120         {
    121             readint(u);readint(v);readint(w);
    122             addage(u,v,w);addage(v,u,w);
    123         }
    124         dfs(1);
    125         printf("%d\n",ans);
    126     }
    127     return 0;
    128 }
    View Code
  • 相关阅读:
    UVA10302 【Summation of Polynomials】
    小Z 系列 解题报告
    Dsu on tree
    轻重链剖分
    二分图匹配
    题解 P2455 【[SDOI2006]线性方程组】
    闫氏DP分析法
    扩展域并查集
    bindColumn、bindParam与bindValue的区别
    如何获取二维数组的列数
  • 原文地址:https://www.cnblogs.com/gryzy/p/6164712.html
Copyright © 2020-2023  润新知