华华和月月种树

链接:https://ac.nowcoder.com/acm/contest/7199/A
来源:牛客网
 

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

华华看书了解到,一起玩养成类的游戏有助于两人培养感情。所以他决定和月月一起种一棵树。因为华华现在也是信息学高手了,所以他们种的树是信息学意义下的。
华华和月月一起维护了一棵动态有根树,每个点有一个权值。刚开存档的时候,树上只有 0 号节点,权值为 0 。接下来有两种操作:
操作 1:输入格式1 i1\ i1 i,表示月月氪金使节点 i 长出了一个新的儿子节点,权值为0,编号为当前最大编号 +1(也可以理解为,当前是第几个操作 1,新节点的编号就是多少)。
操作 2:输入格式 2 i a2 \ i \ a2 i a,表示华华上线做任务使节点 i 的子树中所有节点(即它和它的所有子孙节点)权值加 a 。
但是月月有时会检查华华有没有认真维护这棵树,会作出询问:
询问 3:输入格式3 i3\ 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≤M≤4×1051\le M\le 4\times 10^51≤M≤4×105,保证操作1的数量不超过10510^5105,保证操作2中的参数a满足1≤a≤9991\le a\le 9991≤a≤999

思路:离线+树状数组。

预处理:将输入建成树后前序遍历,使每个节点及其子树的序号连续,

树状数组:节点+子树的大小就是这个节点最后的根节点的位置。

新建边:将这个节点值变为0,再将其子树更新(减去这个节点的值)

更新节点:正常的树状数组更新,更新范围是该节点位置到该节点最后根节点位置

输出节点值:输出该节点值

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 4e5 + 10;

struct node{
	int op, p, v;
}nod[N];

int idx, h[N], e[N], ne[N];

void add(int a, int b)
{
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx++;
}

int cnt;
int tim;
int order[N];
int size[N];

void dfs(int u)
{
	order[u] = ++tim;//这样节点的序号在树状数组中是连续的 
	size[u] = 1;
	for(int i=h[u]; i!=-1; i=ne[i])
	{
		int j = e[i];
		dfs(j);
		size[u] += size[j];
	}
}

int lowbit(int x)
{
	return -x & x;
}

int tree[N];

void add_tree(int a, int b, int v)//树状数组更新 
{
	while(a <= tim) tree[a] += v, a += lowbit(a);
	while(b <= tim) tree[b] += -v, b += lowbit(b);
}

int query(int x)
{
	int rul = 0;
	while(x) rul += tree[x], x -= lowbit(x);
	return rul;
}

int main()
{
	memset(h, -1, sizeof h);
	int n;
	cin>>n;
	for(int i=0; i<n; i++)
	{
		cin>>nod[i].op>>nod[i].p;
		if(nod[i].op == 1) add(nod[i].p, ++cnt);//建树 
		else if(nod[i].op == 2) cin>>nod[i].v;
	}
		
	dfs(0);//前序遍历 
	cnt = 0;
	
	for(int i=0; i<n; i++)
	{
		if(nod[i].op == 1) 
		{
			cnt++;
			add_tree(order[cnt], order[cnt]+1, -query(order[cnt]));//跟新单个节点值 
		}
		else if(nod[i].op == 2)
		{
			int a = nod[i].p;
			add_tree(order[a], order[a]+size[a], nod[i].v);//更新节点及其子值 
		}
		else
		{
			cout<<query(order[nod[i].p])<<endl;
		}
	}
	
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个比较简单的数学题,可以用矩阵快速幂求解。以下是 C++ 代码实现: ```c++ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int MAXN = 2; const int MOD = 1e9 + 7; struct Matrix { LL m[MAXN][MAXN]; Matrix() { memset(m, 0, sizeof(m)); } Matrix operator * (const Matrix& b) const { Matrix c; for (int i = 0; i < MAXN; ++i) { for (int j = 0; j < MAXN; ++j) { for (int k = 0; k < MAXN; ++k) { c.m[i][j] = (c.m[i][j] + m[i][k] * b.m[k][j]) % MOD; } } } return c; } } base, res; Matrix qpow(Matrix a, int b) { Matrix ans; for (int i = 0; i < MAXN; ++i) { ans.m[i][i] = 1; } while (b) { if (b & 1) { ans = ans * a; } a = a * a; b >>= 1; } return ans; } LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); } int main() { LL a, b, n; cin >> a >> b >> n; if (n == 1) { cout << a << endl; } else if (n == 2) { cout << b << endl; } else { base.m[0][0] = base.m[0][1] = base.m[1][0] = 1; res = qpow(base, n - 2); LL ans = gcd(a * res.m[0][0] % MOD + b * res.m[1][0] % MOD, b * res.m[1][0] % MOD + b * res.m[1][1] % MOD); cout << ans << endl; } return 0; } ``` 在这段代码中,我们定义了一个 `Matrix` 结构体,它表示一个 $2\times2$ 的矩阵。其中重载了 `*` 运算符,实现了矩阵乘法。 然后,我们定义了一个矩阵快速幂函数 `qpow`,用于求解矩阵的 $n$ 次方。 最后,在 `main` 函数中,我们通过快速幂求出矩阵 $base$ 的 $n-2$ 次方,然后根据题目要求求出 $\gcd(F_N, F_{N+1})$ 并输出即可。 需要注意的是,当 $n=1$ 或 $n=2$ 时,直接输出 $a$ 或 $b$ 即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值