链接:https://ac.nowcoder.com/acm/contest/392/H

来源:牛客网

时间限制:C/C++ 2秒,其他语言4秒

空间限制:C/C++ 131072K,其他语言262144K

64bit IO Format: %lld

题目描述

华华看书了解到,一起玩养成类的游戏有助于两人培养感情。所以他决定和月月一起种一棵树。因为华华现在也是信息学高手了,所以他们种的树是信息学意义下的。

华华和月月一起维护了一棵动态有根树,每个点有一个权值。刚开存档的时候,树上只有 0 号节点,权值为 0 。接下来有两种操作:

操作 1:输入格式1\ i1 i,表示月月氪金使节点 i 长出了一个新的儿子节点,权值为0,编号为当前最大编号 +1(也可以理解为,当前是第几个操作 1,新节点的编号就是多少)。

操作 2:输入格式 2 \ i \ a2 i a,表示华华上线做任务使节点 i 的子树中所有节点(即它和它的所有子孙节点)权值加 a 。

但是月月有时会检查华华有没有认真维护这棵树,会作出询问:

询问 3:输入格式3\ i3 i,华华需要给出 i 节点此时的权值。

华华当然有认真种树了,不过还是希望能写个程序以备不时之需。

输入描述:

第一行一个正整数M,接下来M行,每行先输入一个正整数O表示操作类型,再输入一个非负整数i表示操作或询问的节点编号,如果O=2,再输入一个正整数a。

输出描述:

对于每个询问3,输出一个非负整数表示询问的答案。

示例1

输入

复制

9

1 0

2 0 1

3 0

3 1

1 0

1 1

2 0 2

3 1

3 3

输出

复制

1

1

3

2

备注:

1\le M\le 4\times 10^51≤M≤4×10

5

,保证操作1的数量不超过10^510

5

,保证操作2中的参数a满足1\le a\le 9991≤a≤999

思路:

先按照题目把每个节点建立出来,形成一个完整的树,

然后dfs遍历树得到dfn序,同时维护出以节点i为根的子树节点个数cntson[i],然后根据dfn序列的性质一个节点i为根的子树是一个连续的序列,且序列长度为cntson[i]

,所以建立线段树来维护整个数的节点值,

我们从1~m以此离线处理命令,对于每一个加节点的过程,我们把这个节点的权值清零就可以消除掉建立这个节点之前的操作对这个节点的权值影响。

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int* p);
const int maxn = 400010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
struct node1
{
int op;
int x;
int y;
} info[maxn];
int m;
std::vector<int> son[maxn];
int n = 1;
int id[maxn];
int cnt = 0;
int cntson[maxn];
void dfs(int x, int pre)
{
cntson[x] = 1;
id[x] = ++cnt;
for (auto y : son[x])
{
if (y != pre)
{
dfs(y, x);
cntson[x] += cntson[y];
}
}
}
struct node
{
int l, r;
ll sum;
ll laze;
} segment_tree[maxn << 2];
void pushup(int rt)
{
segment_tree[rt].sum = segment_tree[rt << 1].sum + segment_tree[rt << 1 | 1].sum;
}
void pushdown(int rt)
{
if (segment_tree[rt].laze)
{
ll num = segment_tree[rt].laze;
segment_tree[rt << 1 | 1].laze += num;
segment_tree[rt << 1].laze += num;
segment_tree[rt << 1 | 1].sum += num * (segment_tree[rt << 1 | 1].r - segment_tree[rt << 1 | 1].l + 1);
segment_tree[rt << 1].sum += num * (segment_tree[rt << 1].r - segment_tree[rt << 1].l + 1);
segment_tree[rt].laze = 0ll;
}
}
void build(int rt, int l, int r)
{
segment_tree[rt].l = l;
segment_tree[rt].r = r;
if (l == r)
{
segment_tree[rt].sum = 0;
segment_tree[rt].laze = 0;
return ;
}
int mid = (r + l) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void change(int rt, int l, int r, ll val)
{
pushdown(rt);
if (segment_tree[rt].l == l && segment_tree[rt].r == r && l == r)
{
segment_tree[rt].sum = 0;
return ;
}
int mid = (segment_tree[rt].l + segment_tree[rt].r) >> 1;
if (l <= mid)
{
change(rt << 1, l, r, val);
}
if (r >= mid + 1)
{
change(rt << 1 | 1, l, r, val);
}
pushup(rt);
}
void update(int rt, int l, int r, ll val)
{
pushdown(rt);
if (l <= segment_tree[rt].l && segment_tree[rt].r <= r )
{
segment_tree[rt].sum += 1ll * (segment_tree[rt].r - segment_tree[rt].l + 1) * val;
segment_tree[rt].laze += val;
return ;
}
int mid = (segment_tree[rt].l + segment_tree[rt].r) >> 1;
if (l <= mid)
{
update(rt << 1, l, r, val);
}
if (r >= mid + 1)
{
update(rt << 1 | 1, l , r, val);
}
pushup(rt);
}
ll query(int rt, int l, int r)
{
pushdown(rt);
if (segment_tree[rt].l == l && segment_tree[rt].r == r)
{
return segment_tree[rt].sum;
}
int mid = (segment_tree[rt].l + segment_tree[rt].r) >> 1;
ll res = 0ll;
if (mid >= l)
{
res += query(rt << 1, l, r);
}
if (r >= mid + 1)
{
res += query(rt << 1 | 1, l, r);
}
return res;
}
int main()
{
//freopen("D:\\common_text\\code_stream\\in.txt","r",stdin);
//freopen("D:\\common_text\\code_stream\\out.txt","w",stdout);
scanf("%d", &m);
repd(i, 1, m)
{
scanf("%d %d", &info[i].op, &info[i].x); info[i].x++;
if (info[i].op == 2)
{
scanf("%d", &info[i].y);
} else if (info[i].op == 1)
{
son[info[i].x].push_back(++n);
info[i].y = n;
}
}
dfs(1, -1);
int now = 2;
build(1, 1, n);
repd(i, 1, m)
{
if (info[i].op == 1)
{
change(1, id[now], id[now], 0);
now++;
} else if (info[i].op == 3)
{
printf("%lld\n", query(1, id[info[i].x], id[info[i].x]) );
} else
{
update(1, id[info[i].x], id[info[i].x] + cntson[info[i].x] - 1, info[i].y);
}
} return 0;
} inline void getInt(int* p) {
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
}
else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}

牛客小白月赛12 H 华华和月月种树 (离线dfs序+线段树)的更多相关文章

  1. 牛客小白月赛12 H 华华和月月种树

    题目链接: 题意:有三个操作 操作 1:表示节点 i 长出了一个新的儿子节点,权值为0,编号为当前最大编号 +1(也可以理解为,当前是第几个操作 1,新节点的编号就是多少). 操作 2:表示华华上线做 ...

  2. 牛客小白月赛12 I 华华和月月逛公园 (tarjian 求桥)

    链接:https://ac.nowcoder.com/acm/contest/392/I 来源:牛客网 华华和月月逛公园 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K, ...

  3. 牛客小白月赛12 I 华华和月月逛公园 Tarjan算法求隔边

    题目链接:https://ac.nowcoder.com/acm/contest/392/I 题意:给你一个连通的无向图,问图的隔边有多少条 输入:N,M分别是点数和边数 之后M行每行两个正整数u,v ...

  4. 牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树)

    牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树) 链接:https://ac.nowcoder.com/acm/problem/15706 现在需要您来帮忙维护这个名册, ...

  5. 牛客小白月赛12 H(dfs序+线段树),F(分块思想+bit),J(二分)

    H 华华和月月种树 链接:https://ac.nowcoder.com/acm/contest/392/H 思路:先得到整棵树最终的形态,在这棵树上进行三种操作,用dfs跑下,第二种操作就直接对最终 ...

  6. 牛客小白月赛12 F 华华开始学信息学 (分块+树状数组)

    链接:https://ac.nowcoder.com/acm/contest/392/F来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 32768K,其他语言65536K ...

  7. 牛客网 牛客小白月赛12 B.华华教月月做数学-A^B mod P-快速幂+快速乘

    链接:https://ac.nowcoder.com/acm/contest/392/B来源:牛客网 华华教月月做数学 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其 ...

  8. 牛客小白月赛12 C 华华给月月出题 (积性函数,线性筛)

    链接:https://ac.nowcoder.com/acm/contest/392/C 来源:牛客网 华华给月月出题 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K, ...

  9. 牛客小白月赛12 J 月月查华华的手机 (序列自动机模板题)

    链接:https://ac.nowcoder.com/acm/contest/392/J 来源:牛客网 题目描述 月月和华华一起去吃饭了.期间华华有事出去了一会儿,没有带手机.月月出于人类最单纯的好奇 ...

随机推荐

  1. JAVA各种框架插件常用端口:redis、MySQL、rabbitmq、elasticsearch、tomcat等等

    默认端口号 应用 21 FTP(文件传输) 22 SSH(安全登录).SCP(文件传输).端口重定向 23 Telnet(远程登录) 80 HTTP服务器 1433 SQL Server数据库serv ...

  2. [转帖]VIM常用快捷键

    VIM常用快捷键 https://www.cnblogs.com/markleaf/p/7808817.html 快捷键能够显著的提高工作效率 一.移动光标 h,j,k,l 上,下,左,右ctrl-e ...

  3. LC 752 Open the Lock

    由于这个问题,涉及了很多知识,例如数据结构里面的哈希表,c++中的迭代器,因此,需要对于每一个疑惑逐一击破. 问题描述 You have a lock in front of you with 4 c ...

  4. php学习历程1——注册、登录(面向过程、面向对象)

    首先放一张天空之城 Php入门来的第一个小项目,首先做的是一个简陋的文章管理系统.有登录.注册.文章list.添加文章.修改文章.删除文章.分页这几个小功能. 面向过程的编码 面向对象的编码 首先做的 ...

  5. scoket模块 粘包问题 tcp协议特点 重启服务器会遇到地址被占用问题

    scoket()模块函数用法 import socket socket.socket(socket_family,socket_type,protocal=0) 获取tcp/ip套接字 tcpsock ...

  6. python-day7(正式学习)

    目录 数字类型内置方法 整形内置方法(int) 常用操作+内置方法 是否可变 浮点型内置方法(float) 常用操作+内置方法 是否可变 字符串内置方法 常用操作+内置方法 是否可变 数字类型内置方法 ...

  7. 基于PriorityQueue(优先队列)解决TOP-K问题

    TOP-K问题是面试高频题目,即在海量数据中找出最大(或最小的前k个数据),隐含条件就是内存不够容纳所有数据,所以把数据一次性读入内存,排序,再取前k条结果是不现实的. 下面我们用简单的Java8代码 ...

  8. Python 风格指南

    https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/contents/ 目前个人遵循的基本规范 ...

  9. C#:Guid.NewGuid()和DateTime.Now该选择哪个???

    直接上代码: namespace ConsoleApp1 { class Program { static void Main(string[] args) { Console.WriteLine(& ...

  10. 【原创】大数据基础之Gobblin(2)持久化kafka到hdfs

    gobblin 0.10 想要持久化kafka到hdfs有很多种方式,比如flume.logstash.gobblin,其中flume和logstash是流式的,gobblin是批处理式的,gobbl ...