Codeforces Round #434 (Div. 1) -E Arkady and a Nobody-men

14 篇文章 0 订阅
8 篇文章 0 订阅
Codeforces传送门
洛谷传送门

题目描述

Arkady words in a large company. There are nn employees working in a system of a strict hierarchy. Namely, each employee, with an exception of the CEO, has exactly one immediate manager. The CEO is a manager (through a chain of immediate managers) of all employees.

Each employee has an integer rank. The CEO has rank equal to 1 1 1 , each other employee has rank equal to the rank of his immediate manager plus 1 1 1 .

Arkady has a good post in the company, however, he feels that he is nobody in the company’s structure, and there are a lot of people who can replace him. He introduced the value of replaceability. Consider an employee a a a and an employee b b b , the latter being manager of aa (not necessarily immediate). Then the replaceability r ( a , b ) r(a,b) r(a,b) of a a a with respect to b b b is the number of subordinates (not necessarily immediate) of the manager b b b , whose rank is not greater than the rank of a a a . Apart from replaceability, Arkady introduced the value of negligibility. The negligibility z a z_{a} za of employee aa equals the sum of his replaceabilities with respect to all his managers, i.e. img, where the sum is taken over all his managers b b b .

Arkady is interested not only in negligibility of himself, but also in negligibility of all employees in the company. Find the negligibility of each employee for Arkady.

输入输出格式

输入格式:

The first line contains single integer n n n ( 1 ≤ n ≤ 5 ⋅ 1 0 5 1\le n\le 5·10^{5} 1n5105) — the number of employees in the company.

The second line contains n n n integers p 1 , p 2 , . . . , p n p_{1},p_{2},...,p_{n} p1,p2,...,pn ( 0 ≤ p i ≤ n 0\le p_{i}\le n 0pin ), where p i = 0 p_{i}=0 pi=0 if the i i i -th employee is the CEO, otherwise p i p_{i} pi equals the id of the immediate manager of the employee with id i i i . The employees are numbered from 1 1 1 to n n n . It is guaranteed that there is exactly one 0 0 0 among these values, and also that the CEO is a manager (not necessarily immediate) for all the other employees.

输出格式:

Print n n n integers — the negligibilities of all employees in the order of their ids: z 1 , z 2 , . . . , z n z_{1},z_{2},...,z_{n} z1,z2,...,zn.

输入输出样例

输入样例#1:
4
0 1 2 1
输出样例#1:
0 2 4 2 
输入样例#2:
5
2 3 4 5 0
输出样例#2:
10 6 3 1 0 
输入样例#3:
5
0 1 1 1 3
输出样例#3:
0 3 3 3 5 

说明

Consider the first example:

  • The CEO has no managers, thus z 1 = 0 z_{1}=0 z1=0 .
  • r ( 2 , 1 ) = 2 r(2,1)=2 r(2,1)=2 (employees 2 2 2 and 4 4 4 suit the conditions, employee 3 3 3 has too large rank). Thus z 2 = r ( 2 , 1 ) = 2 z_{2}=r(2,1)=2 z2=r(2,1)=2.
  • Similarly,$ z_{4}=r(4,1)=2$ .
  • r ( 3 , 2 ) = 1 r(3,2)=1 r(3,2)=1 (employee 3 3 3 is a subordinate of 2 2 2 and has suitable rank). r ( 3 , 1 ) = 3 r(3,1)=3 r(3,1)=3(employees 2 2 2 , 3 3 3 , 4 4 4 suit the conditions). Thus z 3 = r ( 3 , 2 ) + r ( 3 , 1 ) = 4 z_{3}=r(3,2)+r(3,1)=4 z3=r(3,2)+r(3,1)=4.

题目大意

给你一棵有根树, 设 b b b a a a的祖先节点, r ( a , b ) r(a,b) r(a,b)表示在 b b b子树中不超过 a a a深度的点的个数(不包括 a a a自己), 求对于所有点的 z ( i ) = ∑ j ∈ a n c e s t o r ( i ) r ( i , j ) z(i)=\sum_{j\in ancestor(i)}r(i,j) z(i)=jancestor(i)r(i,j)

解题分析

很容易发现每个点 a a a对于其他点 b b b( d e p [ a ] ≤ d e p [ b ] dep[a]\le dep[b] dep[a]dep[b])的贡献就是 d e p [ l c a ( a , b ) ] dep[lca(a,b)] dep[lca(a,b)], 所以将所有点按深度从小到大排序, 每次处理同一深度的点, 在其到根节点的路径上区间 + 1 +1 +1, 然后查询其到根节点的路径上的权值和即可, 总复杂度 O ( n l o g 2 ( n ) ) O(nlog^2(n)) O(nlog2(n)), 卡卡常就过了。

这里有一种 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))的做法。我们可以发现 z ( i ) = z ( f a t [ i ] ) + d e p [ i ] + ∑ d e p [ i ] = d e p [ j ] d e p [ l c a ( i , j ) ] z(i)=z(fat[i])+dep[i]+\sum_{dep[i]=dep[j]}dep[lca(i,j)] z(i)=z(fat[i])+dep[i]+dep[i]=dep[j]dep[lca(i,j)],那么实际上我们只需要考虑同深度的点之间的贡献。

将同深度的点按 D F S DFS DFS序排序, 那么可以发现对于一个排在第 i i i位的点, 其前面的点从 1 1 1开始, 它们的 l c a lca lca的深度是递增的, 这样我们就可以维护一个单调栈, 维护其 l c a lca lca深度, 同时记录数量, 扫过去即可。 最后再将数组翻转过来, 统计从后往前的贡献即可。

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <vector>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 500500
#define ll long long
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
int dot, cnt, root, dc;
int head[MX], dep[MX], fat[MX], son[MX], siz[MX], topf[MX], sta[MX], dp[MX], ct[MX], dfn[MX];
ll ans[MX];
struct Edge {int to, nex;} edge[MX << 1];
IN void add(R int from, R int to) {edge[++cnt] = {to, head[from]}, head[from] = cnt;}
std::vector <int> dat[MX];
bool cmp(R int x, R int y) {return dfn[x] < dfn[y];}
void DFS(R int now)
{
    siz[now] = 1; dfn[now] = ++dc;
    for (R int i = head[now]; i; i = edge[i].nex)
    {
        if (edge[i].to == fat[now]) continue;
        dep[edge[i].to] = dep[now] + 1;
        fat[edge[i].to] = now;
        DFS(edge[i].to);
        siz[now] += siz[edge[i].to];
        if (siz[edge[i].to] > siz[son[now]]) son[now] = edge[i].to;
    }
}
void DFS(R int now, R int grand)
{
    topf[now] = grand;
    if (!son[now]) return;
    DFS(son[now], grand);
    for (R int i = head[now]; i; i = edge[i].nex)
    {
        if (edge[i].to == fat[now] || edge[i].to == son[now]) continue;
        DFS(edge[i].to, edge[i].to);
    }
}
IN int query(R int x, R int y)
{
    W (topf[x] ^ topf[y])
    {
        if (dep[topf[x]] < dep[topf[y]]) std::swap(x, y);
        x = fat[topf[x]];
    }
    return dep[x] < dep[y] ? x : y;
}
IN void solve(R int d)
{
    ll res = 0;
    R int top, lca, now;
    for (R int i = 0; i < dat[d].size(); ++i)
    {
        now = dat[d][i];
        if (!i) sta[top = 1] = now, dp[1] = ct[1] = 0;
        else
        {
            W (233)
            {
                lca = query(sta[top], now);
                if (dep[lca] >= dp[top])
                {
                    sta[++top] = now;
                    dp[top] = dep[lca] + 1;
                    ct[top] = i; break;
                }
                res -= 1ll * (ct[top] - ct[top - 1]) * dp[top];
                --top;
            }
            res += 1ll * (ct[top] - ct[top - 1]) * dp[top];
            ans[now] += res;
        }
    }
}
int main(void)
{
    in(dot); int a;
    for (R int i = 1; i <= dot; ++i)
    {
        in(a);
        if (!a) root = i;
        else add(i, a), add(a, i);
    }
    DFS(root), DFS(root, root);
    for (R int i = 1; i <= dot; ++i) dat[dep[i]].push_back(i);
    for (R int i = 1; i < dot; ++i)
    {
        if (!dat[i].size()) break;
        std::sort(dat[i].begin(), dat[i].end(), cmp);
        for (R int j = 0; j < dat[i].size(); ++j) ans[dat[i][j]] += ans[fat[dat[i][j]]] + i;
        solve(i); std::reverse(dat[i].begin(), dat[i].end());
        solve(i);
    }
    for (R int i = 1; i <= dot; ++i) printf("%I64d ", ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值