D. Alyona and a tree 公式转换 + 分块暴力

http://codeforces.com/problemset/problem/740/D

对于每一对<u, v>。设dis[u]表示root到点u的距离,那么dis<u去v>就是dis[v] - dis[u],

就是在它的儿子中找出有多少个v使得dis[v] - dis[u] <= a[v]。然后,因为如果v确定了,那么dis[v]和a[v]就确定了。

所以把公式转换为dis[v] - a[v] <= dis[u]。

那么可以暴力枚举每一个u,然后在其儿子中找有多少个数小于等于它,这个可以直接暴力分块。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 2e5 + 20;
struct node {
    int u, v, w;
    int tonext;
}e[maxn];
int first[maxn];
int num;
void add(int u, int v, int w) {
    ++num;
    e[num].u = u;
    e[num].v = v;
    e[num].w = w;
    e[num].tonext = first[u];
    first[u] = num;
}
int a[maxn];
int ans[maxn];
LL dp[maxn];
struct LIST {
    int id;
    LL val;
}List[maxn];
int lenList;
int DFN;
int L[maxn];
int R[maxn];
void dfs(int cur) {
    List[++lenList].id = cur;
//    List[lenList].val = a[cur];
    ++DFN;
    L[cur] = DFN;
    for (int i = first[cur]; i; i = e[i].tonext) {
        int v = e[i].v;
        dp[v] = dp[e[i].u] + e[i].w;
        dfs(v);
    }
    R[cur] = DFN;
}
LL tosort[maxn];
void work() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= n - 1; ++i) {
        int fa, w;
        scanf("%d%d", &fa, &w);
        add(fa, i + 1, w);
    }
    dfs(1);
    for (int i = 1; i <= lenList; ++i) {
        List[i].val = dp[List[i].id] - a[List[i].id];
        tosort[i] = List[i].val;
//        printf("%d ", List[i].id);
//        printf("%d %d\n", L[List[i].id], R[List[i].id]);
    }
    int magic = (int)sqrt(lenList);
    for (int i = 1; i <= lenList;) {
        if (i + magic - 1 <= lenList) {
            sort(tosort + i, tosort + i + magic);
        } else break;
        i += magic;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = L[i] + 1; j <= R[i];) {
            if (j % magic == 1 && j + magic - 1 <= R[i]) {
                int pos = upper_bound(tosort + j, tosort + j + magic, dp[i]) - (tosort + j - 1);
                ans[i] += pos - 1;
                j += magic;
            } else {
                if (dp[i] >= List[j].val) {
                    ans[i]++;
                }
                j++;
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        printf("%d ", ans[i]);
    }
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}

时间: 2024-10-13 03:45:19

D. Alyona and a tree 公式转换 + 分块暴力的相关文章

Codeforces 739B Alyona and a tree (树上路径倍增及差分)

题目链接 Alyona and a tree 弄了好几个小时终于Accepted了,之后发现这个题是Div1的. 比较考验我思维的一道好题. 首先,做一遍DFS预处理出t[i][j]和d[i][j].t[i][j]表示从第i个节点到离他第2^j近的祖先,d[i][j]表示从i开始到t[i][j]的路径上的路径权值总和. 在第一次DFS的同时,对节点x进行定位(结果为dist(x, y)<=a(y))的离x最远的x的某个祖先,然后进行O(1)的差分. 第一次DFS完成后,做第二次DFS统计答案(统

Light OJ 1339 Strongest Community(分块暴力)

In a strange city, houses are built in a straight line one after another. There are several communities in the city. Each community consists of some consecutivehouses such that every house belongs to exactly one community. The houses are numbered fro

Codeforces#86D Powerful array(分块暴力)

Description An array of positive integers a1,?a2,?...,?an is given. Let us consider its arbitrary subarray al,?al?+?1...,?ar, where 1?≤?l?≤?r?≤?n. For every positive integer s denote by Ks the number of occurrences of s into the subarray. We call the

LeetCode 226 Invert Binary Tree(转换二叉树)

翻译 将下图中上面的二叉树转换为以下的形式.详细为每一个左孩子节点和右孩子节点互换位置. 原文 如上图 分析 每次关于树的题目出错都在于边界条件上--所以这次细致多想了一遍: void swapNode(TreeNode* tree) { if (tree == NULL || (tree->left == NULL && tree->right == NULL)) {} else if (tree->left == NULL && tree->ri

HDU - 6394 Tree(树分块+倍增)

http://acm.hdu.edu.cn/showproblem.php?pid=6394 题意 给出一棵树,然后每个节点有一个权值,代表这个点可以往上面跳多远,问最少需要多少次可以跳出这颗树 分析 先dfs一次得到dfs序,然后按dfs序分块.倍增计算从某点跳x到哪个点,用cn保存它跳出这一块需要的次数,ne保存跳出这块会去的点.然后块内就暴力修改了.复杂度nsqrt(n); #include <iostream> #include <cstdio> #include <

CF739B Alyona and a tree 树上差分

题目描述 \(Alyona有一棵有 n个节点的树.这棵树的根节点是 1.在每个节点里,Alyona写了一个正整数,在节点 i 她写了正整数a_i .另外,她在这棵树上的每条边上写了一个正整数(不同边上可能有不同的数). 让我们定义 dist(v,u) 作为从 v 到 u 的简单路径上的边权和. 当且仅当 u 在 v 的子树中并且 dist(v,u)<=a_u,顶点 v 控制顶点 u(v!=u) .Alyona想在某些顶点定居.为了做到这件事,她想知道在每个节点 v 能控制几个节点.\) 对于\(

codeforces 682C Alyona and the Tree DFS

这个题就是在dfs的过程中记录到根的前缀和,以及前缀和的最小值 #include <cstdio> #include <iostream> #include <ctime> #include <vector> #include <cmath> #include <map> #include <stack> #include <queue> #include <algorithm> #include

【CF739B】Alyona and a tree(树上差分,二分,树形DP)

题意:给出一棵有根树,树上每个点.每条边都有一个权值. 现在给出"控制"的定义:对一个点u,设点v在其子树上,且dis(u,v)≤av,则称u控制v. 要求求出每个点控制了多少个点 n (1?≤?n?≤?2·105).  (1?≤?ai?≤?109) 1?≤?pi?≤?n, 1?≤?wi?≤?109) 思路:在学校CF有时上不去不知道为什么 对于确定的点i,计算它对哪些点有贡献 dis[i]-dis[u]<=a[i] dis[u]<=a[i]-dis[i]满足二分性 倍增枚

Codeforces 682C Alyona and the Tree(树形DP)

题目大概说给一棵点有权.边也有权的树.一个结点v不高兴当且仅当存在一个其子树上的结点u,使得v到u路径上的边权和大于u的权值.现在要不断地删除叶子结点使得所有结点都高兴,问最少删几个叶子结点. 一开始题目看错了,以为说的是v到u路径上的边权和小于v的权值,然后想出了个解法:从根开始DFS,找高兴的结点,递归过程中在set插入各个祖先结权值,递归返回时从set中删除,而如果set里面最小的元素小于当前结点的路径和那么这个结点就不能要直接return,另外还用到一个简单的数学原理——两个数同时加上相