Codeforces1076E. Vasya and a Tree(dfs+离线+树状数组维护)

题目链接:传送门

题目:

E. Vasya and a Tree
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Vasya has a tree consisting of n
vertices with root in vertex 1. At first all vertices has 0

written on it.

Let d(i,j)
be the distance between vertices i and j, i.e. number of edges in the shortest path from i to j. Also, let‘s denote k-subtree of vertex x — set of vertices y

such that next two conditions are met:

    x

is the ancestor of y
(each vertex is the ancestor of itself);
d(x,y)≤k

    . 

Vasya needs you to process m
queries. The i-th query is a triple vi, di and xi. For each query Vasya adds value xi to each vertex from di-subtree of vi

.

Report to Vasya all values, written on vertices of the tree after processing all queries.
Input

The first line contains single integer n
(1≤n≤3?105

) — number of vertices in the tree.

Each of next n?1
lines contains two integers x and y (1≤x,y≤n) — edge between vertices x and y

. It is guarantied that given graph is a tree.

Next line contains single integer m
(1≤m≤3?105

) — number of queries.

Each of next m
lines contains three integers vi, di, xi (1≤vi≤n, 0≤di≤109, 1≤xi≤109) — description of the i

-th query.
Output

Print n
integers. The i-th integers is the value, written in the i

-th vertex after processing all queries.
Examples
Input
Copy

5
1 2
1 3
2 4
2 5
3
1 1 1
2 0 10
4 10 100

Output
Copy

1 11 1 100 0 

Input
Copy

5
2 3
2 1
5 4
3 4
5
2 0 4
3 10 1
1 2 3
2 3 10
1 1 7

Output
Copy

10 24 14 11 11 

Note

In the first exapmle initial values in vertices are 0,0,0,0,0
. After the first query values will be equal to 1,1,1,0,0. After the second query values will be equal to 1,11,1,0,0. After the third query values will be equal to 1,11,1,100,0.

题目大意:

  给定一棵有N个节点的有向树,根节点为1。

  有M次操作,对以vi为根的深度为di的子树上的所有节点权值加xi

  1≤n,m≤3?105,1 ≤ vi ≤ n,0 ≤ di ≤ 109,1 ≤ xi ≤ 109

思路:

  离线处理,把每个更新都放到对应的vi上,然后从节点1开始dfs。

  dfs时遇到一个节点后,把这个节点所有的“操作”都拿出来:

  对于每个“操作”,更新当前深度到本次操作影响的最大深度[dep, dep+di]区间内的值加上xi,回溯的时候再减掉xi。这里可以用树状数组维护。

  每个节点的答案就是被搜索到之后,“操作”结束之后的当前深度的值。

  到这里就已经可以AC了。

  但是树状数组的logn的复杂度还可以继续优化,用一个前缀和数组sum维护,更新[dep, dep+di]区间时,只要让sum[dep] += xi,sum[dep+di+1] -= xi,就可以实现整个区间的加减了。

  有人问(就是我):“中间的明明没有加上去啊???”

  “。。。对,但是你是一个个跑过来的啊,把之前的前缀加过来不就好了?”(w神)

  period。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAX_NM = 65;

int n, m, t, act;
string opt[10];
string acts[10];
ll F[MAX_NM], A[60][MAX_NM][MAX_NM], AAA[MAX_NM][MAX_NM];

inline int num(int i, int j) {
    return (i-1)*m + j;
}

void mul(ll f[MAX_NM], ll a[MAX_NM][MAX_NM]) {
    ll c[MAX_NM];
    memset(c, 0, sizeof c);
    for (int j = 0; j < MAX_NM; j++)
        for (int k = 0; k < MAX_NM; k++)
            c[j] += f[k] * a[k][j];
    memcpy(f, c, sizeof c);
}

void mulb(ll a[MAX_NM][MAX_NM], ll b[MAX_NM][MAX_NM]) {
    ll c[MAX_NM][MAX_NM];
    memset(c, 0, sizeof c);
    for (int i = 0; i < MAX_NM; i++)
        for (int j = 0; j < MAX_NM; j++)
            for (int k = 0; k < MAX_NM; k++)
                c[i][j] += a[i][k]*b[k][j];
    memcpy(a, c, sizeof c);
}

void mulself(ll a[MAX_NM][MAX_NM]) {
    ll c[MAX_NM][MAX_NM];
    memset(c, 0, sizeof c);
    for (int i = 0; i < MAX_NM; i++)
        for (int j = 0; j < MAX_NM; j++)
            for (int k = 0; k < MAX_NM; k++)
                c[i][j] += a[i][k]*a[k][j];
    memcpy(a, c, sizeof c);
}

void init()
{
    memset(A, 0, sizeof A);
    memset(F, 0, sizeof F);
    F[0] = 1;
    for (int k = 0; k < 60; k++) {
        A[k][0][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                int index = opt[i-1][j-1] - ‘0‘;
                int indey = k % acts[index].size();
                char ch = acts[index][indey];

                if (isupper(ch)) {
                    switch (ch) {
                        case ‘N‘:
                            if (i-1 >= 1)
                                A[k][num(i, j)][num(i-1, j)] = 1; break;
                        case ‘S‘:
                            if (i+1 <= n)
                                A[k][num(i, j)][num(i+1, j)] = 1; break;
                        case ‘W‘:
                            if (j-1 >= 1)
                                A[k][num(i, j)][num(i, j-1)] = 1; break;
                        case ‘E‘:
                            if (j+1 <= m)
                                A[k][num(i, j)][num(i, j+1)] = 1; break;
                        case ‘D‘:
                            A[k][num(i, j)][num(i, j)] = 0;
                    }
                }
                if (isdigit(ch)) {
                    A[k][num(i, j)][num(i, j)] = 1;
                    A[k][0][num(i, j)] = ch - ‘0‘;
                }

            }
        }
    }
    for (int i = 0; i < MAX_NM; i++)
        AAA[i][i] = 1;
    for (int k = 0; k < 60; k++)
        mulb(AAA, A[k]);
}

int main()
{
    cin >> n >> m >> t >> act;
    for (int i = 0; i < n; i++)
        cin >> opt[i];
    for (int i = 0; i < act; i++)
        cin >> acts[i];
    init();
    int q = t/60;
    int r = t%60;
    // t = q*60 + r;
    for (; q; q >>= 1) {
        if (q&1)
            mul(F, AAA);
        mulself(AAA);
    }
    for (int i = 0; i < r; i++)
        mul(F, A[i]);
    ll ans = 0;
    for (int i = 1; i < MAX_NM; i++)
        ans = max(ans, F[i]);
    cout << ans << endl;
    return 0;
}

参考博客:

  wyboooo‘s blog

原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9959934.html

时间: 2024-10-12 12:49:31

Codeforces1076E. Vasya and a Tree(dfs+离线+树状数组维护)的相关文章

1076E/Educational Codeforces Round 54-E. Vasya and a Tree&lt;&lt;dfs序 树状数组

题意 给定一棵树,初始每个节点权值为零,q次更改,每次修改将以v为顶点的深度为d的子树全部加上x,最后输出所有节点的权重. 思路 题目只要求每个点最后的值,那么经过观察,发现一个点最后的权值大小只与他的父节点的更新有关,那么我们就只需要考虑他的父节点到他这条链上的情况,把这条链拿出来成为线段,然后维护后缀和就能得到此点上的权值.每个节点的贡献为给$[h,h+d]$增加$x$,所以维护时,只要在$h+d$点上加上$x$即可. 但是问题考察的是一棵树,我们就需要动态来完成这条链,我们采用dfs序去扫

Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+树状数组

C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/problem/C Description Iahub likes trees very much. Recently he discovered an interesting tree named propagating tree. The tree consists of n nodes numb

[poj3321]Apple Tree(dfs序+树状数组)

Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 26762   Accepted: 7947 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been

POJ 3321 Apple Tree DFS序 + 树状数组

多次修改一棵树节点的值,或者询问当前这个节点的子树所有节点权值总和. 首先预处理出DFS序L[i]和R[i] 把问题转化为区间查询总和问题.单点修改,区间查询,树状数组即可. 注意修改的时候也要按照dfs序修改,因为你查询就是按照dfs查的,所以修改也要用dfs序修改 L[i]是唯一的. #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <

HDU 3333 Turing Tree(离线树状数组)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5014    Accepted Submission(s): 1777 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems

BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状数组维护, DFS到的查询点就回答询问.时间复杂度O(|ACAM|+QlogQ) ------------------------------------------------------------------------------------------- #include<cstdio>

HDU 5156 - Harry and Christmas tree (dfs序+离线树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=5156 BC#25的C题. 题意是:给出一颗大小为n的树,以1为根,然后给出m次染色,每次将节点u加上一种颜色(一个节点可以有多个颜色). 最后查询树上每个节点对应子树上包含的不同颜色数量. 当时这场比赛没有做,回来看一下题目,没看标解就试着敲了一遍,于是解题思路从一开始就走上了不归路. 标解是O(n+m)的方法,主要思路是将问题转为:一次染色表示将u到根节点的路径都染上这种颜色. 但这样做需要去重,因为如果u

POJ-3321 Apple Tree 【DFS序+树状数组】

Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree. The tree has N forks which are connected by branches.

【BZOJ3653】谈笑风生 离线+树状数组+DFS序

[BZOJ3653]谈笑风生 Description 设T 为一棵有根树,我们做如下的定义: ? 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称“a比b不知道高明到哪里去了”. ? 设a 和 b 为 T 中的两个不同节点.如果 a 与 b 在树上的距离不超过某个给定常数x,那么称“a 与b 谈笑风生”. 给定一棵n个节点的有根树T,节点的编号为1 到 n,根节点为1号节点.你需要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a;b;c)满足: 1. a.b和 c为 T