• 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≤3105
    
    ) — 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≤3105
    
    ) — 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.
    View Code

    题目大意:

      给定一棵有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。

    UPDATE:

      其实就是dfs的时候顺便维护前缀和,遇到当前深度的时候把当前深度的权值(可能是负的)都捡起来,然后进入下一层,回溯的时候再把捡起来的权值都丢掉。

    代码:

    #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;
    }
    View Code

    参考博客:

      wyboooo's blog

  • 相关阅读:
    1015,存储过程,视图
    1009,数据库查询,聚合函数,日期时间函数
    1008,数据库表格创建,名称,格式

    公历和农历转换的JS代码
    面向对象之封装
    HTML之锚点
    HTML之css+div
    HTML基础
    SQL之定义变量
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9959934.html
Copyright © 2020-2023  润新知