点分治

点分治&动态点分治

Tags:数据结构

作业部落

评论地址


点分治

一、板子

鉴于没有人会看我的博客学习点分治,所以就不详细解说算法了,提供一个板子逼着自己背下来
板子:[luogu3806]【模板】点分治1

求树上是否存在距离为\(K\)的路径,多组询问

点分治支持以下函数
Getroot Getdis Calc solve

1.找重心
void Getroot(int x,int fa)
{
    siz[x]=1;mx[x]=0;
    for(int i=head[x];~i;i=a[i].next)
    {
        int R=a[i].to;
        if(R==fa||vis[R]) continue;
        Getroot(R,x);
        siz[x]+=siz[R];
        mx[x]=max(mx[x],siz[R]);
    }
    mx[x]=max(mx[x],sum-siz[x]);
    if(mx[x]<mx[root]) root=x;
}
2.把树上距离存进临时数组
void Getdis(int x,int fa)
{
    dis[++cnt]=dep[x];
    for(int i=head[x];~i;i=a[i].next)
    {
        int R=a[i].to;
        if(vis[R]||R==fa) continue;
        dep[R]=dep[x]+a[i].w;
        Getdis(R,x);
    }
}
3.点分治不同题的区别就在于Calc函数
void Calc(int x,int d,int op)
{
    cnt=0;
    dep[x]=d;
    Getdis(x,0);
    sort(dis+1,dis+cnt+1);
    for(int i=1;i<=M;i++)
    {
        int l=1,r=cnt;
        while(l<r)
            if(dis[l]+dis[r]>K[i]) r--;
            else
            {
                if(dis[l]+dis[r]==K[i])
                    for(int k=r;dis[k]==dis[r]&&k>=l;k--)
                        Yes[i]+=op;
                l++;
            }
    }
}
4.递归计算,分层找重心
void Solve(int x)
{
    Calc(x,0,1);
    vis[x]=1;int tt=sum;
    for(int i=head[x];~i;i=a[i].next)
    {
        int R=a[i].to;
        if(vis[R]) continue;
        Calc(R,a[i].w,-1);
        sum=siz[R]>siz[x]?tt-siz[x]:siz[R];//siz要注意了————Cwen
        root=0;
        Getroot(R,x);Solve(root);
    }
}
5.\(main\)函数中的调用
int main()
{
    root=0;mx[0]=sum=N;
    Getroot(1,0);Solve(root);
}
注意有些题不能容斥

二、用处

在我所做过的题中,他可以用来求解树上路径问题
1.长为\(k\)(小于\(k\))的路径条数(以及这条路径的最少边数)
2.长为三的倍数的路径条数
3.路径点权之积\(\%p=k\)的字典序最小点对

动态点分治

区别在于递归时要记录上级重心,由此产生的父子关系构成点分树
于是在点分树上维护很多很多东西就可以支持动态修改了
大家看看这题-幻想乡战略游戏(动态维护带权重心)

题单

点分治

动态点分治

转载于:https://www.cnblogs.com/xzyxzy/p/9481496.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值