zoukankan      html  css  js  c++  java
  • CF955F Heaps 题解

    Codeforces
    Luogu

    Description.

    给定一棵有根树,定义 \(F_k(i)\) 表示第 \(i\) 号点子树内最大的满 \(k\) 叉树,求

    \[\sum_{i=1}^n\sum_{j=1}^nF_j(i) \]

    Range.

    \(n\le 3\times 10^5\)

    Solution.

    首先考虑暴力 \(dp\),设 \(dp_{i,j}\) 表示 \(F_j(i)\)
    然后,我们考虑每次转移,\(dp_k\) 从它儿子中找到第 \(k\) 大,转移过来。
    看上去很难维护,复杂度只能做到 \(O(n^2\log n)\)(基排优化一个 \(\log\)

    然后,我们考虑观察性质,好像并没有什么性质。
    我们发现,如果 \(k\ne 1\),那么就必然有 \(dp_k(x)\le O(\log n)\)
    考虑经典套路,就是把 \(dp\) 的答案维和 \(dp\) 维互换,状态数变成了 \(n\log n\)
    状态相当于变成了 \(dp_{k}(x)\) 表示在第 \(x\) 个点,度数至多为多少时,它有 \(x\) 层。
    然后,我们转移的时候,要找到 \(dp_{k}(y)\ge cnt(y)\)\(cnt(y)\) 表示在 \(x\) 的孩子内,有几个比它小。
    然后直接暴力转移即可,复杂度 \(O(n\log ^2n)\)

    Coding.

    点击查看代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }/*}}}*/
    const int N=300005;struct edge{int to,nxt;}e[N<<1];int et,head[N];
    int n,ln[N],dp[N][20];ll rs=0;
    inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
    inline void dfs0(int x,int fa)
    {
    	ln[x]=1;for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa)
    		dfs0(e[i].to,x),ln[x]=max(ln[e[i].to]+1,ln[x]);
    	vector<int>v;dp[x][1]=n,rs+=ln[x];for(int k=2;k<20;k++)
    	{
    		v.clear();for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa)
    			v.push_back(dp[e[i].to][k-1]);
    		sort(v.begin(),v.end(),greater<int>());int id=0;
    		for(;id<(int)v.size()&&v[id]>=id+1;id++);
    		dp[x][k]=id;
    	}
    }
    inline void dfs1(int x,int fa)
    {
    	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) dfs1(e[i].to,x);
    	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa)
    		for(int k=1;k<20;k++) dp[x][k]=max(dp[x][k],dp[e[i].to][k]);
    }
    int main()
    {
    	read(n);for(int i=1,x,y;i<n;i++) read(x),read(y),adde(x,y),adde(y,x);
    	dfs0(1,0),dfs1(1,0);for(int i=1;i<=n;i++) for(int j=1;j<20;j++) rs+=max(dp[i][j]-1,0);
    	return printf("%lld\n",rs),0;
    }
    
  • 相关阅读:
    感谢燕玲,搞定了客商名称输入即开始检测是否存在
    一步一步学习sqlserverBI多维数据库建立
    sql语句创建文件夹、判断文件夹、创建数据库、表、
    自定义Silverlight DataGrid行列:Defining Columns for a Silverlight DataGrid
    精简版XP SP3安装IIS6,过程坎坷,以此文献给有需要的朋友
    SilverLight 4页面跳转大全(转载)
    如何修改.net framework(转载)
    定义silverlight报表样式Styling a Silverlight Chart
    Silverlight Toolkit DataGrid 单元格内容对齐样式
    一步一步学习sqlserver BI数据仓库设计
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15110050.html
Copyright © 2011-2022 走看看