[Codeforces]860E Arkady and a Nobody-men
屯一个虚树的板子,顺便总结一下这样的题型。
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的更多相关文章
- Arkady and a Nobody-men CodeForces - 860E (虚树)
大意: 给定有根树, 根节点深度为$1$. 定义$r(a,b)$为$b$子树内深度不超过$a$的节点数$-1$ 定义$z_a$为$a$的所有祖先的$r$之和. 对于所有点求出$z$的值. 一个点$y$ ...
- Codeforces 1326F2 - Wise Men (Hard Version)(FWT+整数划分)
Codeforces 题目传送门 & 洛谷题目传送门 qwq 这题大约是二十来天前 AC 的罢,为何拖到此时才完成这篇题解,由此可见我是个名副其实的大鸽子( 这是我上 M 的那场我没切掉的 F ...
- 【Codeforces Round #476 (Div. 2) [Thanks, Telegram!] C】Greedy Arkady
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 枚举那个人收到了几次糖i. 最好的情况显然是其他人都只收到i-1次糖. 然后这个人刚好多收了一次糖 也即 (i-1)kx + x & ...
- Codeforces Round #327 (Div. 2) B. Rebranding 水题
B. Rebranding Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/591/problem ...
- codeforces 591B Rebranding (模拟)
Rebranding Problem Description The name of one small but proud corporation consists of n lowercase E ...
- 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 ...
- 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 ...
- Codeforces#543 div2 A. Technogoblet of Fire(阅读理解)
题目链接:http://codeforces.com/problemset/problem/1121/A 真·阅读理解 题意就是 有n个人 pi表示他们的强度 si表示他们来自哪个学校 现在Arkad ...
- 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 ...
随机推荐
- caffe使用ctrl-c不能保存模型
caffe使用Ctrl-c 不能保存模型: 是因为使用的是 tee输出日志 解决方法:kill -s SIGINT <proc_id> 或者使用 GLOG_log_dir=/path/to ...
- Pandas速查手册中文版
本文翻译自文章: Pandas Cheat Sheet - Python for Data Science ,同时添加了部分注解. 对于数据科学家,无论是数据分析还是数据挖掘来说,Pandas是一个非 ...
- Python爬虫之urllib模块2
Python爬虫之urllib模块2 本文来自网友投稿 作者:PG-55,一个待毕业待就业的二流大学生. 看了一下上一节的反馈,有些同学认为这个没什么意义,也有的同学觉得太简单,关于Beautiful ...
- Netty事件监听和处理(下)
上一篇 介绍了事件监听.责任链模型.socket接口和IO模型.线程模型等基本概念,以及Netty的整体结构,这篇就来说下Netty三大核心模块之一:事件监听和处理. 前面提到,Netty是一个NIO ...
- JWT(JSON Web Token) 多网站的单点登录,放弃session
多个网站之间的登录信息共享, 一种解决方案是基于cookie - session的登录认证方式,这种方式跨域比较复杂. 另一种替代方案是采用基于算法的认证方式, JWT(json web token) ...
- 2.x与3.x差异、条件语句、数据类型、其他
一.输入(raw_input)=====>python2.x版本 #!/usr/bin/env python # -*- coding: utf-8 -*- # 将用户输入的内容赋值给 name ...
- C# 后台构造json数据
前后台传值一般情况下,都会用到json类型的数据,比较常见,但是每次用到的时候去网上找比较麻烦,所以自己记录一下,下次直接用. 构造的json串格式,如下: [{","name&q ...
- 关于css的层叠上下文和层叠顺序问题
关于css的层叠上下文和层叠样式问题 最近在项目中遇到了一个让我欲仙欲死的问题,我给项目中的图片设置了一个淡入效果,几opacity变化,但当我在它的上面有一个定位元素时,动画结束后,定位元素居然被遮 ...
- python/ORM操作详解
一.python/ORM操作详解 ===================增==================== models.UserInfo.objects.create(title='alex ...
- 线程的同步控制(Synchronization)
临界区(Critical Sections) 摘要 临界区(Critical Section) 用来实现"排他性占有".适合范围时单一进程的各线程之间. 特点 一个局部对象,不是一 ...