码迷,mamicode.com
首页 > 其他好文 > 详细

树上点分治学习记录

时间:2015-06-17 21:40:08      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:

跟着机房的潮流学了点分治,发现这个东西其实还蛮好写的,学会思想,很容易YY出来。直接上习题。
POJ 1741 TREE
点分治的模板题,首先设点x到当前子树跟root的距离为gx,则满足gx+gyk可以加进答案,但是注意如果x,y在同一棵子树中,就要删去对答案的贡献,以为x,y会在其所在的子树中在计算一次。注意无根树转有根树的过程,需要选取树的重心防止复杂度从O(nlog2n)退化为O(n2) code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 100000
using namespace std;
struct hp{
    int u,v,w;
}a[20001];
struct hq{
    int size;
}tree[10001];
bool done[10001];
int point[10001],next[20001];
int len[10001];
int n,m,e=0,t=0;
int size,root,sizenow,tot,ans=0;
void add(int u,int v,int w)
{
    e++; a[e].u=u; a[e].v=v; a[e].w=w; next[e]=point[u]; point[u]=e;
    e++; a[e].u=v; a[e].v=u; a[e].w=w; next[e]=point[v]; point[v]=e;
}
void findsize(int now,int last)
{
    int i,tmp=0;
    sizenow++;
    for (i=point[now];i;i=next[i])
      if (a[i].v!=last&&!done[a[i].v])
        findsize(a[i].v,now);
}
void findroot(int now,int last)
{
    int i,tmp=0;
    tree[now].size=1; tmp=0;
    for (i=point[now];i;i=next[i])
      if (a[i].v!=last&&!done[a[i].v])
        {
          findroot(a[i].v,now);
          tree[now].size+=tree[a[i].v].size;
          if (tree[a[i].v].size>tmp)
            tmp=tree[a[i].v].size;
        }
    if (sizenow-tree[now].size>tmp) tmp=sizenow-tree[now].size;
    if (tmp<size)
      {root=now; size=tmp;}
}
void findroad(int now,int last,int road)
{
    int i,tmp=0;
    len[++t]=road; 
    if (road>m) return;
    for (i=point[now];i;i=next[i])
      if (a[i].v!=last&&!done[a[i].v])
        findroad(a[i].v,now,road+a[i].w);
}
int calc(int k)
{
    int i,l,r,ret=0;
    sort(len+1,len+t+1);
    for (l=1,r=t;l<r;)
      {
        if (len[l]+len[r]<=k) ret+=r-l++;
        else r--;
      }
    return ret;
}
void work(int now)
{
    int i;
    sizenow=0; t=0;  size=inf;
    findsize(now,0);
    findroot(now,0);
    findroad(root,0,0);
    done[root]=true;
    ans+=calc(m);
    for (i=point[root];i;i=next[i])
      if (!done[a[i].v])
        {
          t=0; sizenow=0; size=inf;
          findroad(a[i].v,0,0);
          ans-=calc(m-2*a[i].w);
          findsize(a[i].v,0);
          findroot(a[i].v,0);
          work(a[i].v);    
        }
}
int main()
{
    int i,x,y,z;
    scanf("%d%d",&n,&m);
    while (n!=0&&m!=0)
      {
        e=0; ans=0;
        memset(point,0,sizeof(point));
        memset(done,false,sizeof(done));
        for (i=1;i<=n-1;++i)
         {
           scanf("%d%d%d",&x,&y,&z);
           add(x,y,z);
         }
        work(1);
        printf("%d\n",ans);
        scanf("%d%d",&n,&m);
      }
}

树上点分治学习记录

标签:

原文地址:http://blog.csdn.net/lcomyn/article/details/46537243

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!