屯一个虚树的板子,顺便总结一下这样的题型。

Description

  给定一棵n个节点的有根树,在输入数据通过给出每个节点的父亲来表示这棵树。若某个节点的父亲为0,那么该节点即为根。现在对于每个点,询问它的每个祖先的所有深度不超过该节点的儿子的数量的总和。

Input

  第一行一个整数n。第二行n个整数,表示每个节点的父亲pi。

Output

  输出一行n个整数,表示每个节点的答案。

Sample Input

  5
  2 3 4 5 0

Sample Output

  10 6 3 1 0

HINT

  1<= n <=5*10^5,0<= pi <= n,保证有且仅有一个pi = 0。

Solution

  这道题的思路是显而易见的。

  对于每个节点,它的贡献是它到根的一条链(给它的所有祖先的子树大小+1)。

  每个节点的询问也是它到根的那一条链。

  至于深度不超过询问节点,我们发现,对于每个节点,只有深度小等于它的节点才对它有贡献,而且是一定有贡献。

  所以我们把所有点按深度排序,一层一层地做。插入一层,询问一层。

  用上树链剖分你就会在O(nlog2n)的时间内T掉该题。(如果你用树剖过了当我没说)

  然后我们考虑怎么将它优化。

  对于修改链的问题,我们通常可以通过逆向思考,将其变为子树修改,复杂度可以从O(nlog2n)降为O(nlogn)。

  询问很显然是很容易转化的,每个点都询问它的所有祖先,相当于每个点都对它的所有子节点加上答案贡献。

  而对于修改我们则要分析一下:

    

  如图,我们做到了第5层,计算红色节点对祖先子树大小的贡献。

  我们发现两个节点的贡献会在他们的lca处合并,那么这样一来正好构成一棵以该深度的点为叶节点的虚树!(即绿色节点)

  虚树上每个节点x到它父亲的这条链上被红色节点的贡献val[x]都是相等的,

  因此虚树上每个节点x对该节点的子节点们的贡献就是val[x]*(dep[x]-dep[fa[x]])!

  虚树的点数和叶节点数同级,所以总复杂度为O(nlogn)。

  然而通过观察,我们还可以发现每一层的节点答案对下一层是具有递推关系的。

  一个结点的答案可以由它父亲的答案加上该节点所在层的所有节点对它的贡献,这个我们同样可以用虚树解决。

  搞出虚树上每个节点被红色节点的贡献,然后从虚树根出发,往下dfs,到底层节点就计算一下答案即可。

  如果你用上tarjan求lca和一些骚排序(如果你愿意的话)可以把时间复杂度优化到O(n)。(你大可把这句话当成是小C在口胡)

  代码是第二种(用上线段树的)做法:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define ll long long
#define MN 500005
#define MS 20
using namespace std;
struct edge{int nex,to;}e[MN];
int dfbg[MN],dfed[MN],dep[MN],hr[MN],q[MN],siz[MN],fa[MS][MN],b[MN],u[MN];
ll t[MN],ans[MN];
vector <int> d[MN];
int dfn,pin,bin,tp,n,rt; inline int read()
{
int n=,f=; char c=getchar();
while (c<'' || c>'') {if(c=='-')f=-; c=getchar();}
while (c>='' && c<='') {n=n*+c-''; c=getchar();}
return n*f;
} inline void ins(int x,int y) {e[++pin]=(edge){hr[x],y}; hr[x]=pin;} void dfs(int x,int depth)
{
dfbg[x]=++dfn; dep[x]=depth;
d[depth].push_back(x);
for (register int i=hr[x];i;i=e[i].nex)
dfs(e[i].to,depth+);
dfed[x]=dfn;
} int lca(int x,int y)
{
register int i,k;
if (dep[x]<dep[y]) swap(x,y);
for (k=dep[x]-dep[y],i=;k;k>>=,++i)
if (k&) x=fa[i][x];
if (x==y) return x;
for (i=MS-;i>=;--i)
if (fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];
return fa[][x];
} inline void pushs(int x) {while (tp&&dfbg[x]>dfed[q[tp]]) --tp; if (tp) ins(q[tp],x); q[++tp]=x;}
inline int lowbit(int x) {return x&-x;}
inline void getadd(int x,int z) {for (;x<=n;x+=lowbit(x)) t[x]+=z;}
inline ll getsum(int x) {ll lt=; for (;x;x-=lowbit(x)) lt+=t[x]; return lt;} void dp(int x,int fat)
{
siz[x]=u[x];
for (register int i=hr[x];i;i=e[i].nex)
dp(e[i].to,x),siz[x]+=siz[e[i].to];
getadd(dfbg[x]+, 1LL*siz[x]*(dep[x]-dep[fat]));
getadd(dfed[x]+,-1LL*siz[x]*(dep[x]-dep[fat]));
} bool cmp(int x,int y) {return dfbg[x]<dfbg[y];} int main()
{
register int i,j;
n=read(); bin=;
for (i=;i<=n;++i) ins(fa[][i]=read(),i),b[++bin]=i;
for (i=;i<=n;++i) if (!fa[][i]) rt=i;
for (i=;i<MS;++i)
for (j=;j<=n;++j) fa[i][j]=fa[i-][fa[i-][j]];
dfs(rt,);
for (i=;d[i].size();++i)
{
for (j=;j<=bin;++j) hr[b[j]]=u[b[j]]=;
tp=pin=bin=;
for (j=;j<d[i].size();++j) ++u[b[++bin]=fa[][d[i][j]]];
bin=unique(b+,b+bin+)-b-;
for (j=;j<bin;++j) b[bin+j]=lca(b[j],b[j+]);
bin=bin*-; sort(b+,b+bin+,cmp);
bin=unique(b+,b+bin+)-b-;
for (j=;j<=bin;++j) pushs(b[j]);
dp(q[],);
for (j=;j<d[i].size();++j) ans[d[i][j]]=getsum(dfbg[d[i][j]]);
}
for (i=;i<=n;++i) printf("%I64d ",ans[i]);
}

Last Word

  感觉全程打得最难受的是倍增求lca,小C一直觉得自己的lca写得奇丑无比。

[Codeforces]860E Arkady and a Nobody-men的更多相关文章

  1. Arkady and a Nobody-men CodeForces - 860E (虚树)

    大意: 给定有根树, 根节点深度为$1$. 定义$r(a,b)$为$b$子树内深度不超过$a$的节点数$-1$ 定义$z_a$为$a$的所有祖先的$r$之和. 对于所有点求出$z$的值. 一个点$y$ ...

  2. Codeforces 1326F2 - Wise Men (Hard Version)(FWT+整数划分)

    Codeforces 题目传送门 & 洛谷题目传送门 qwq 这题大约是二十来天前 AC 的罢,为何拖到此时才完成这篇题解,由此可见我是个名副其实的大鸽子( 这是我上 M 的那场我没切掉的 F ...

  3. 【Codeforces Round #476 (Div. 2) [Thanks, Telegram!] C】Greedy Arkady

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 枚举那个人收到了几次糖i. 最好的情况显然是其他人都只收到i-1次糖. 然后这个人刚好多收了一次糖 也即 (i-1)kx + x & ...

  4. Codeforces Round #327 (Div. 2) B. Rebranding 水题

    B. Rebranding Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/591/problem ...

  5. codeforces 591B Rebranding (模拟)

    Rebranding Problem Description The name of one small but proud corporation consists of n lowercase E ...

  6. Codeforces 768A Oath of the Night's Watch

    A. Oath of the Night's Watch time limit per test:2 seconds memory limit per test:256 megabytes input ...

  7. Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2)(A.暴力,B.优先队列,C.dp乱搞)

    A. Carrot Cakes time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  8. Codeforces#543 div2 A. Technogoblet of Fire(阅读理解)

    题目链接:http://codeforces.com/problemset/problem/1121/A 真·阅读理解 题意就是 有n个人 pi表示他们的强度 si表示他们来自哪个学校 现在Arkad ...

  9. Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) D. High Load 构造

    D. High Load 题目连接: http://codeforces.com/contest/828/problem/D Description Arkady needs your help ag ...

随机推荐

  1. JavaScript简写技巧总结

    在日常工作中,JavaScript一些常用的简写技巧,将直接影响到我们的开发效率,现将常用技巧整理如下: 1. 空(null, undefined)验证     当我们创建了一个新的变量,我们通常会去 ...

  2. php的控制器链

    控制器之间协同工作就形成了控制器链· 比如在一个控制器的方法中,创建另外一个·控制器,创建对象,然后调用第二个控制器方法,那么在第一个控制器分配给视图的变量,在 第二个控制器的方法中对应的视图也是可以 ...

  3. C# 一个初学者对 依赖注入 IOC 的理解( 含 Unity 的使用)

    通过 人打电话 来谈谈自己对IOC的理解 版本1.0 public class Person { public AndroidPhone Phone { get; set; } public void ...

  4. Web移动端适配总结

    移动端适配的相关概念以及几种方案总结 适配相关概念 布局视口(layout viewport):html元素的上一级容器即顶级容器,用于解决页面在手机上显示的问题.大部分移动设备都将这个视口分辨率设置 ...

  5. 从Mybatis源码理解jdk动态代理默认调用invoke方法

    一.背景最近在工作之余,把开mybatis的源码看了下,决定自己手写个简单版的.实现核心的功能即可.写完之后,执行了一下,正巧在mybatis对Mapper接口的动态代理这个核心代码这边发现一个问题. ...

  6. bugfree,CDbConnection 无法开启数据库连线: SQLSTATE[HY000] [2003] Can't connect to MySQL server on '192.168.0.99' (4)

    安装bugfree后,访问报错:CDbConnection 无法开启数据库连线: SQLSTATE[HY000] [2003] Can't connect to MySQL server on '19 ...

  7. nginx配置反向代理详细教程(windows版)

    内容属于原创,如果需要转载,还请注明地址:http://www.cnblogs.com/j-star/p/8785334.html Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(I ...

  8. spring cloud eureka显示ip

    eureka.instance.preferIpAddress=trueeureka.instance.instance-id=${spring.cloud.client.ipAddress}:${s ...

  9. 用js来实现那些数据结构(数组篇03)

    终于,这是有关于数组的最后一篇,下一篇会真真切切给大家带来数据结构在js中的实现方式.那么这篇文章还是得啰嗦一下数组的相关知识,因为数组真的太重要了!不要怀疑数组在JS中的重要性与实用性.这篇文章分为 ...

  10. python request

    python request a. 客户端向服务端发送多层字典的值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 obj =  ...