题目链接:传送门

题目:

E. Vasya and a Tree
time limit per test
seconds
memory limit per test
megabytes
input
standard input
output
standard output Vasya has a tree consisting of n
vertices with root in vertex . At first all vertices has 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
(≤n≤⋅ ) — number of vertices in the tree. Each of next n−
lines contains two integers x and y (≤x,y≤n) — edge between vertices x and y . It is guarantied that given graph is a tree. Next line contains single integer m
(≤m≤⋅ ) — number of queries. Each of next m
lines contains three integers vi, di, xi (≤vi≤n, ≤di≤, ≤xi≤) — 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 Output
Copy Input
Copy Output
Copy Note In the first exapmle initial values in vertices are ,,,,
. After the first query values will be equal to ,,,,. After the second query values will be equal to ,,,,. After the third query values will be equal to ,,,,.

题目大意:

  给定一棵有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 = ; int n, m, t, act;
string opt[];
string acts[];
ll F[MAX_NM], A[][MAX_NM][MAX_NM], AAA[MAX_NM][MAX_NM]; inline int num(int i, int j) {
return (i-)*m + j;
} void mul(ll f[MAX_NM], ll a[MAX_NM][MAX_NM]) {
ll c[MAX_NM];
memset(c, , sizeof c);
for (int j = ; j < MAX_NM; j++)
for (int k = ; 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, , sizeof c);
for (int i = ; i < MAX_NM; i++)
for (int j = ; j < MAX_NM; j++)
for (int k = ; 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, , sizeof c);
for (int i = ; i < MAX_NM; i++)
for (int j = ; j < MAX_NM; j++)
for (int k = ; k < MAX_NM; k++)
c[i][j] += a[i][k]*a[k][j];
memcpy(a, c, sizeof c);
} void init()
{
memset(A, , sizeof A);
memset(F, , sizeof F);
F[] = ;
for (int k = ; k < ; k++) {
A[k][][] = ;
for (int i = ; i <= n; i++) {
for (int j = ; j <= m; j++) {
int index = opt[i-][j-] - '';
int indey = k % acts[index].size();
char ch = acts[index][indey]; if (isupper(ch)) {
switch (ch) {
case 'N':
if (i- >= )
A[k][num(i, j)][num(i-, j)] = ; break;
case 'S':
if (i+ <= n)
A[k][num(i, j)][num(i+, j)] = ; break;
case 'W':
if (j- >= )
A[k][num(i, j)][num(i, j-)] = ; break;
case 'E':
if (j+ <= m)
A[k][num(i, j)][num(i, j+)] = ; break;
case 'D':
A[k][num(i, j)][num(i, j)] = ;
}
}
if (isdigit(ch)) {
A[k][num(i, j)][num(i, j)] = ;
A[k][][num(i, j)] = ch - '';
} }
}
}
for (int i = ; i < MAX_NM; i++)
AAA[i][i] = ;
for (int k = ; k < ; k++)
mulb(AAA, A[k]);
} int main()
{
cin >> n >> m >> t >> act;
for (int i = ; i < n; i++)
cin >> opt[i];
for (int i = ; i < act; i++)
cin >> acts[i];
init();
int q = t/;
int r = t%;
// t = q*60 + r;
for (; q; q >>= ) {
if (q&)
mul(F, AAA);
mulself(AAA);
}
for (int i = ; i < r; i++)
mul(F, A[i]);
ll ans = ;
for (int i = ; i < MAX_NM; i++)
ans = max(ans, F[i]);
cout << ans << endl;
return ;
}

参考博客:

  wyboooo's blog

Codeforces1076E. Vasya and a Tree(dfs+离线+动态维护前缀和)的更多相关文章

  1. CF Edu54 E. Vasya and a Tree DFS+树状数组

    Vasya and a Tree 题意: 给定一棵树,对树有3e5的操作,每次操作为,把树上某个节点的不超过d的子节点都加上值x; 思路: 多开一个vector记录每个点上的操作.dfs这颗树,同时以 ...

  2. CodeForces-1076E Vasya and a Tree

    CodeForces - 1076E Problem Description: Vasya has a tree consisting of n vertices with root in verte ...

  3. HH的项链 树状数组动态维护前缀

    #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const ...

  4. BZOJ2690: 字符串游戏(平衡树动态维护Dfs序)

    Description 给定N个仅有a~z组成的字符串ai,每个字符串都有一个权值vi,有M次操作,操作分三种: Cv x v':把第x个字符串的权值修改为v' Cs x a':把第x个字符串修改成a ...

  5. Vasya and a Tree CodeForces - 1076E(线段树+dfs)

    I - Vasya and a Tree CodeForces - 1076E 其实参考完别人的思路,写完程序交上去,还是没理解啥意思..昨晚再仔细想了想.终于弄明白了(有可能不对 题意是有一棵树n个 ...

  6. CF1076E:Vasya and a Tree(DFS&差分)

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

  7. Vasya and a Tree CodeForces - 1076E (线段树 + dfs)

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

  8. Codeforces 1076 E - Vasya and a Tree

    E - Vasya and a Tree 思路: dfs动态维护关于深度树状数组 返回时将当前节点的所有操作删除就能保证每次访问这个节点时只进行过根节点到当前节点这条路径上的操作 代码: #pragm ...

  9. BZOJ3159决战——树链剖分+非旋转treap(平衡树动态维护dfs序)

    题目描述 输入 第一行有三个整数N.M和R,分别表示树的节点数.指令和询问总数,以及X国的据点. 接下来N-1行,每行两个整数X和Y,表示Katharon国的一条道路. 接下来M行,每行描述一个指令或 ...

随机推荐

  1. 剑指offer(33)丑数

    题目描述 把只包含因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. 题目分析 ...

  2. pip使用豆瓣的镜像源

    豆瓣镜像地址:https://pypi.douban.com/simple/ 虽然用easy_install和pip来安装第三方库很方便 它们的原理其实就是从Python的官方源pypi.python ...

  3. 百度AI搜索引擎

    一.爬虫协议 与其它爬虫不同,全站爬虫意图爬取网站所有页面,由于爬虫对网页的爬取速度比人工浏览快几百倍,对网站服务器来说压力山大,很容易造成网站崩溃. 为了避免双输的场面,大家约定,如果网站建设者不愿 ...

  4. newcoder 小A的柱状图(单调栈)题解

    题目描述 柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数,分别为a[i] 每个矩形的高度是h[i] ,现在 ...

  5. Java正则中为什么反斜线"\"需要用“\\\\”表示,原因详解。

    首先,我们需要知道在java字符串和正则表达式中,“\”都具有特殊的含义. 一.在Java的字符串中"\"有两个功能 (一)代表特殊字符:\t代表制表符,\n代表换行....等. ...

  6. Learning-Python【23】:面向对象三大特性

    继承 封装 多态

  7. Learning-Python【25】:绑定方法与非绑定方法

    类中定义函数分为了两大类,绑定方法与非绑定方法,它们有一些特殊之处: 1.绑定方法特殊之处:绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入 绑定给对象的方法:这个在面向对象第一篇第六 ...

  8. 【JS面试向】选择排序、桶排序、冒泡排序和快速排序简介

    新年伊始,又到了金三银四的时候了.面对前端越来越多的算法面试题,我简单的整理了一下几种比较常见的数组排序方式,分别介绍其基本原理和优劣势.(ps:才疏学浅,希望大家可以在issues下面指出问题) 选 ...

  9. Centos7初始化脚本

    今天分享一个自己写的一个初始化的小脚本. 编写初始化系统要考虑到系统的版本问题,现在用的比较多的就是centos6和centos7,所以首先要判断一下系统的版本. cat /etc/redhat-re ...

  10. Linux下设置svn开机自启动

    方式一:centos 7 设置svn开机自启动 使用新的systemctl 服务命令  (笔者成功验证过,该方式可行) [root@iZjvr37lpviqbkZ init.d]# vi /lib/s ...