首页 > 其他分享 >点分树

点分树

时间:2023-01-12 10:23:39浏览次数:56  
标签:Rt sz f1 int fa 点分树 dis

黄昏夕阳,铺一片余晖锦缎,远处炊烟袅袅,我们活在这美好温暖的人间。

本文是基于辰星凌的博客QAQ大佬的博客的自己的一些“摘抄”和自己的一些想法

点分治的核心思想在于依据重心划分子连通块,按照分治递归的顺序提一颗新树出来对于每一个找到的重心,将上一层分治时的重心设为它的父亲,得到一颗大小不变、最多 logn 层的重构树


「HNOI2015」开店

维护一颗带点权、边权树,每次给出 \(x,l,r\),查询 \(∑_{l⩽Ay⩽r}dis(x,y)\),其中 \(Ay\) 为 \(y\) 的点权。

\(f1(i,j)=∑_{x∈subtree(i),Ax⩽j}dis(x,i)\)

\(f2(i,j)=∑_{x∈subtree(i),Ax⩽j}dis(x,fai)\)

\(sz(i,j)=∑_{x∈subtree(i),Ax⩽j}1\)

\(G(i,fa_i)= f1(fa_i,k-dis(x,fa_i))−f2(i,k-dis(x,fa_i))+dis(x,fa_i)×(sz(fa_i,k)−sz(i,k))\)

\(f1\)多计算了\(i\)子树内部的,所以减去\(f2\) \(i\)子树内部据\(fa_i\)满足\(f1\)条件的(也就是多算的)

总答案=\(fa_i-i\)子树下距\(fa_i\)小于等于\(k-dis(x,fa_i)\)的+\(dis(x,fa_i)\times\)满足条件点的个数

\(ans(x,k)=f1(x,k)+∑_{i∈fatree(x),fa_i≠0}G(i,fa_i)\)

void solve(ll u){
    dfs1(u);//get size
    if(sz[u]==1){
        cut[u]=1;
        fa[u].push_back({u,0,-1});
        return;
    }//边界条件
    Size=sz[u],mn=INF;
    dfs2(u);//找 重心 
    cut[Rt]=1;//重心已经被删掉 
    fa[Rt].push_back({Rt,0,-1});
    for(ll i=hd[Rt],t=0;i;i=nxt[i]){
        ll y=to[i];
        if(cut[y])continue;//之前已经作为重心被使用过了
        d[y]=val[i];
        dfs3(y,Rt,t);//预处理vector
        son[Rt][t].push_back({INF,0,0});//
        sort(son[Rt][t].begin(),son[Rt][t].end());//按点权排序 
        for(ll j=son[Rt][t].size()-2;j>=0;j--){
            son[Rt][t][j].sz+=son[Rt][t][j+1].sz;//处理后缀和
            son[Rt][t][j].dis+=son[Rt][t][j+1].dis;
        }
        t++;
    }
    for(ll i=hd[Rt];i;i=nxt[i]){
        ll y=to[i];
        if(!cut[y])solve(y);
    }//递归点分治
}

「BZOJ3730」震波

以下用 \(fa_i\) 表示点 \(i\) 在虚树上的父亲,\(subtree(i)\) 为点 \(i\) 在虚树上的子树集合,\(fatree(i)\) 为点 \(i\) 在虚树上的祖先集合,\(dis(i,j)\) 为 \(i,j\) 两点在原树上的距离,\(Ai\) 为点 \(i\) 的点权。

\(f1(i,j)=∑_{x∈subtree(i),dis(x,i)⩽j}Ax\)

即虚树上 i 的子树中与 i 距离小于等于 j 的点权值之和

\(f2(i,j)=∑_{x∈subtree(i),dis(x,fai)⩽j}Ax\)

即虚树上 i 的子树中与 \(fa_i\) 距离小于等于 \(j\) 的点权值之和

在一次查询 \((x,k)\) 中,对于虚树上的一对父子节点 \((i,fa_i)\),\(subtree(fa_i)−subtree(i)\) 对答案的贡献为 \(G(i,fa_i)=f1(fa_i,k−dis(x,fa_i))-f2(i,k−dis(x,fa_i)) \)

\(f1(fa_i,k−dis(x,fa_i))\)包含了多余的i子树的部分

因此后面减去\(f2(i,k−dis(x,fa_i))\) i子树小于等于k−dis(x,fa_i)的部分

\(ans(x,k)=f1(x,k)+ ∑_{i∈fatree(x),fa_i≠0}G(i,fa_i)\)

注意前面那个 \(f1(x,k)\)是因为容斥求和后没有被统计进去,所以要单独算

有一个问题就是:

void solve(int x,int F){//处理重心x所囊括的连通块
    int now=Size;
    vis[x]=1;
    fa[x]=F;
    f1[x].build(now/2+1);
    f2[x].build(now+1);//这个地方大小为什么是now?为什么不是now/2?
    for(int i=hd[x];i;i=a[i].nxt){
        int y=a[i].to;
        if(vis[y]) continue;
        Size=sz[y]>sz[x]?now-sz[x]:sz[y];//注意子连通块大小不要直接用sz[y]
        rt=0;
        mx[rt]=INF;
        getrt(y,0);
        solve(rt,x);
    }    
}

\(Attention\):
在 \(subtree(i)\) 中为重心

所以 \(f1(i,j)\) 中 \(j\) 的值域为 \([0∼now/2]\)

\(f2(i,j)\) 中 \(j\) 的值域为 \([1∼now]\)

[2010国家集训队]Crash的旅游计划

就是和上面那道题差不多了啦~(呕

标签:Rt,sz,f1,int,fa,点分树,dis
From: https://www.cnblogs.com/Aurora1217/p/17045405.html

相关文章

  • 点分治与点分树
    点分治和点分树真的是各种意义上的好东西。不仅好玩,而且写完一看自己的代码5.几kb:“wc我今天搞了好多学习”。在做关于树的题时,我们会遇到一类题型:题目跟路径有关,你找到......
  • 动态点分治(点分树)
    点分树(动态点分治)点分治的核心思想在于依据重心划分子连通块,其良好的性质保证了最多只会分治logn层。有了这一特性,便可使用各种暴力计算答案。那么我们按照分治递归的......