首页 > 其他分享 >4543: [POI2014]Hotel加强版[树形DP+长链剖分]

4543: [POI2014]Hotel加强版[树形DP+长链剖分]

时间:2023-05-31 10:01:47浏览次数:43  
标签:长链 加强版 剖分 int son dep 节点 mx


题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4543

 

解题思路:

长链剖分

定义:

f[i][j]表示以i为根节点的子树,有多少个节点和i的距离是j的.

g[i][j]表示以i为根节点的子树,在子树外一个距离i为j的点可以跟i子树内的两个点组成两两相等的方案数.

那么就有:

f[u][j+1] += f[v][j],  g[u][j+1] += f[u][j+1]*f[v][j],  g[u][j] += g[u][j+1].

所以当u节点继承重儿子son[u]的时候有:f[u][j+1] = f[son[u]][j],g[u][j] = g[son[u]][j+1].

如果我们用指针维护他们的数组首地址,假设f[u] = a,那么f[son[u]] = a+1,假设g[u] = b,那么g[son[u]] = b - 1;

因为长链剖分的性质,所有长链的点长度和==n,所以可以用指针在一维数组上面维护二维数组。

那么ans就可以用f[u][j]*g[v][j+1]和g[u][j+1]*f[v][j]更新,需要注意的是u节点从重儿子继承过来还需加上g[u][0]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e5 + 10;
vector <int> r[mx];
int n,dep[mx],son[mx];
ll tmp[mx<<2],*id = tmp,*f[mx],*g[mx];
ll ans;
void dfs(int u,int fa){
    for(int i=0;i<r[u].size();i++){
        int v = r[u][i];
        if(v==fa) continue;
        dfs(v,u);
        if(dep[v]>dep[son[u]]) son[u] = v;
    }
    dep[u] = dep[son[u]] + 1; 
}
void dp(int u,int fa){
    if(son[u]){
        f[son[u]] = f[u] + 1;
        g[son[u]] = g[u] - 1;
        dp(son[u],u);
    }
    f[u][0] = 1;
    ans += g[u][0];//以u做最高点的方案数,这里处理重儿子的时候可能被忽略
    for(int i=0;i<r[u].size();i++){
        int v = r[u][i];
        if(v==fa||v==son[u]) continue;
        f[v] = id,id += dep[v]<<1;
        g[v] = id,id += dep[v]<<1;
        dp(v,u);
        for(int j=0;j<dep[v];j++){
            ans += g[u][j+1]*f[v][j];
            if(j) ans += f[u][j-1]*g[v][j];
        }
        for(int j=0;j<dep[v];j++){
            g[u][j+1] += f[u][j+1]*f[v][j];
            if(j) g[u][j-1] += g[v][j];
            f[u][j+1] += f[v][j];
        }
    } 
}
int main(){
    scanf("%d",&n);
    int u,v;
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        r[u].push_back(v);
        r[v].push_back(u);
    }
    dfs(1,0);
    f[1] = id,id += dep[1]<<1;
    g[1] = id,id += dep[1]<<1;
    dp(1,0);
    printf("%lld\n",ans);
    return 0;
}

 

标签:长链,加强版,剖分,int,son,dep,节点,mx
From: https://blog.51cto.com/u_12468613/6384525

相关文章

  • 树链剖分
    前言以下内容大多摘抄自董晓算法前置芝士相关定义重儿子:父节点的所有儿子中子树结点数目最多的结点轻儿子:父节点中除了重儿子之外的儿子重边:父结点和重儿子连成的边轻边:父结点和轻儿子连成的边重链:由多条重边连接而成的路径前置数组含义\(fa[u]\):存\(u\)的父节点\(......
  • 树链剖分
    我不会做ppt/ll先来看一棵树:树剖的经典问题:两种操作,一种是将点\(u\)到点\(v\)路径上所有点加上一个值;第二种是查询路径\(u\)到路径\(v\)的点权之和。显然,普通的树上差分已经无法解决这种问题了。于是我们需要一种预处理来降低复杂度。区间修改,这肯定用到线段树,但是......
  • 【iOS开发】后台定位&&socket长链接
    参考:iOS9后台定位无限后台定位注意:这个上架appstore可能会被拒绝,如果你的应用不是和地图类相关的话。目前没想到好的解决方案,有的话请发邮件告诉博主一下,谢谢!!!......
  • Delaunay三角剖分——BW算法
    Delaunay三角剖分定义在数学和计算几何中,对于给定的平面中的离散点集P ,其Delaunay三角剖分DT()满足:空圆性:DT(P)是 唯一 的(任意四点不能共圆),在DT(P)中,任意 三角形的外接圆范围内不会有其它点存在。最大化最小角:在点集P 可能形成的三角剖分中,DT(P)所形成的三角形......
  • [BZOJ4407]于神之怒加强版 CODE
    #include<bits/stdc++.h>#definelllonglong#defineFor(i,a,b)for(lli=(a);i<=(b);++i)#defineRep(i,a,b)for(lli=(a);i>=(b);--i)constllN=1e6+10;usingnamespacestd;constllmod=1e9+7;llvis[N],tot,p[N];voidinit(lln){//质数筛For......
  • P8786 李白打酒加强版 题解
    李白打酒加强版题目大意一开始酒显里有\(2\)斗酒,每遇到一次店就会把酒显里的酒数量(单位:斗)乘\(2\),每遇到一次花就把酒显里的酒喝掉\(1\)斗。这一路上一共遇到店\(n\)次,遇到花\(m\)次,且最后一次遇到的是花,酒显里没有一斗酒了。计算这一路上遇到店和花的顺序总共有......
  • hdu:How far away ?(树链剖分)
    ProblemDescriptionTherearenhousesinthevillageandsomebidirectionalroadsconnectingthem.Everydaypeolealwaysliketoasklikethis“HowfarisitifIwanttogofromhouseAtohouseB”?Usuallyithardtoanswer.Butluckilyintthisvilla......
  • 树链剖分学习笔记
    一棵树,支持:路径加单点查询一般树上链的问题使用树链剖分解决。重链剖分前置知识LCA,线段树定义重儿子:所有儿子中子树最大的儿子为重儿子重边:重儿子之间的连边重链:若干重儿子连成的链性质一棵树可以被剖成若干重链。优先遍历重儿子,所有重链的dfs序连续。重链数量不......
  • 最近公共祖先 树链剖分
    例题:洛谷P3379【模板】最近公共祖先(LCA)https://www.luogu.com.cn/problem/P3379首先是几个概念重儿子:父结点所有子树中最大的子树的根节点(只有一个或没有)轻儿子:父结点除了重儿子以外的所有子结点(没有或有很多个)重边:父结点和重儿子连的边轻边:父结点和轻儿子连的边重链:相接......
  • 最大子矩阵问题 加强版
    给定一个二维的数组(含正数或负数),请从中找出和最大的子矩阵。输入第一行:n,m接下来n行m列,表示一个二维数组输出 和为最大子矩阵的和样例样例输入440-2-7092-62-41-41-180-2样例输出15tips:#include<bits/stdc++.h>usingnamespacestd;l......