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

点分治

时间:2015-06-26 21:07:23      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:

poj1741树上的点对

题目大意:给定一棵树,求树上距离不超过k的点对个数。

思路:点分治模板题。

技术分享
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define maxnode 10005
#define inf 2100000000LL
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},va[maxnode*2]={0},
    siz[maxnode]={0},tot=0,maxn,root,ans=0,k,n;
bool visit[maxnode]={0};
vector<int> dis;
void add(int u,int v,int w)
{
    ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;va[tot]=w;
    ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;va[tot]=w;
}
void getroot(int u,int fa,int nn)
{
    int i,maxsiz=0,j;
    siz[u]=1;
    for (i=point[u];i;i=next[i])
    {
        if (!visit[j=en[i]]&&j!=fa)
        {
            getroot(j,u,nn);siz[u]+=siz[j];
            maxsiz=max(maxsiz,siz[j]);
        }
    }
    maxsiz=max(maxsiz,nn-siz[u]);
    if (maxsiz<maxn)
    {
        maxn=maxsiz;root=u;
    }
}
void getdep(int u,int dep,int fa)
{
    int i;
    dis.push_back(dep);siz[u]=1;
    for (i=point[u];i;i=next[i])
        if (en[i]!=fa&&!visit[en[i]]) 
        {
          getdep(en[i],dep+va[i],u);siz[u]+=siz[en[i]];
        }
}
int cal(int u,int dep)
{
    int sum=0,i,j;    
    dis.clear();getdep(u,dep,0);
    sort(dis.begin(),dis.end());
    for (i=0,j=dis.size()-1;i<j;)
    {
        if (dis[i]+dis[j]<=k) 
        {
          sum+=j-i;++i;
        }
        else --j;
    }
    return sum;
}
void work(int u)
{
    int i,j;
    ans+=cal(u,0);visit[u]=true;
    for (i=point[u];i;i=next[i])
    {
        if (!visit[en[i]])
        {
            ans-=cal(en[i],va[i]);
            maxn=siz[en[i]];
            getroot(en[i],root=0,siz[en[i]]);
            work(root);
        }
    }
}
int main()
{
    freopen("poj1741_tree.in","r",stdin);
    freopen("poj1741_tree.out","w",stdout);
    
    int i,j,u,v,w;
    while(scanf("%d%d",&n,&k)==2)
    {
        if (n==0&&k==0) break;
        tot=0;memset(visit,false,sizeof(visit));
        memset(point,0,sizeof(point));
        for (i=1;i<n;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        maxn=n;ans=0;
        getroot(1,root=0,n);
        work(root);
        printf("%d\n",ans);
    }
}
View Code

 

hdu4670Cube number on a tree 
题目大意:给定一棵树,每个点都有一个权值,可以分为一些给定质数的和(质数个数不超过30),求出一些路径的条数,使路径都满足路上点权乘积是个立方数。 
思路:我们对于每一个点都分解质因数,保存下每种的个数,满足条件的路径就是那些点的相应因数个数相加后%3=0的路径了。 
点分,对每一个点统计路径个数,减去重复的就可以了。 
对于统计答案的部分,我们dfs求出到点到重心路径上的和,把这个30位的数组转成一个三进制数,放到map里。穷举每一个map里面的数,找到互补的数,贡献给答案就可以了。这里注意如果这个数和互补数一样的话,ans的计算方式略有不同。 
对于重复的部分,我们减去的时候要时刻注意变量的含义。 
这道题目的思维和代码量都中等,但是结合起来莫名的很难写(蒟蒻的吐槽),要认真思考好每一个部分的实现。 

 

点分治

标签:

原文地址:http://www.cnblogs.com/Rivendell/p/4603194.html

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