DTOJ2450 梦灵苏魅

58 篇文章 0 订阅

题目

题目描述

紫雅拥有七彩的头发,身穿樱花色的七彩裙子,这种梦幻般的外貌自然能够吸引所有男人的目光
紫雅为了展示自己的才华,开始在这个国家跳起了芭蕾
已知这个国家的城市和道路刚好形成一颗完全二叉树,从位于根节点的城市开始广度优先依次将城市编号为 1 ∼ N 1\sim N 1N
紫雅在这个国家一共表演 M M M天,每天会从某个城市开始,经过若干条道路(不会回头),从而到达某个城市进行芭蕾表演
每个城市都有人口数量 A i A_i Ai,紫雅希望知道,对于她这一天的行动,她所有可能表演的城市的人口之和为多少

输入格式

第一行 2 2 2个正整数 N , M N,M N,M
接下来 N N N行每行 1 1 1个整数 A i A_i Ai,为第 i i i个城市的人口数量
接下来 M M M行每行 2 2 2个正整数 B j , P j B_j, P_j Bj,Pj,表示第j天紫雅的起点城市的编号以及经过的道路的数量

输出格式

M M M行,每行 1 1 1个非负整数 C i C_i Ci,为第 j j j天所有可能表演的城市的人口数量之和
如果不存在这种城市,则答案为 0 0 0

样例

样例输入

7 3
13
7
2
9
5
6
8
1 3
4 2
3 1

样例输出

0
18
27

数据范围与提示

样例解释

第一天: 1 1 1号城市位于该树的根节点。不存在经过 3 3 3条不重复的道路所能到达的城市
第二天: 4 4 4号城市位于该树的叶节点,经过 2 2 2条道路可到达 1 1 1号城市和 5 5 5号城市,故答案为 13 + 5 = 18 13+5=18 13+5=18
第三天: 3 3 3号城市位于 1 1 1号城市的子节点处,经过 1 1 1条道路可到达 1 1 1号城市, 6 6 6号城市和 7 7 7号城市。故答案为 13 + 6 + 8 = 27 13+6+8=27 13+6+8=27

数据范围

对于 50 % 50\% 50%的数据: 1 ⩽ N ⩽ 1023 , 1 ⩽ M ⩽ 1000 1\leqslant N\leqslant 1023,1\leqslant M\leqslant 1000 1N1023,1M1000
对于 100 % 100\% 100%的数据: 1 ⩽ N ⩽ 131071 , 1 ⩽ M ⩽ 100000 1\leqslant N\leqslant 131071,1\leqslant M\leqslant 100000 1N131071,1M100000,且 N = 2 t − 1 , t ∈ N + , 1 ⩽ A i ⩽ 30000 N=2t-1,t\in \N^+,1\leqslant Ai\leqslant 30000 N=2t1,tN+,1Ai30000

题解

f i , j f_{i,j} fi,j为从 i i i出发,往下走 j j j步能到达的点的权值和, g i , j g_{i,j} gi,j为从 i i i出发,往上走 j j j步能到达的点的权值和
所以我们可以直接用DFS求 f f f g g g
最后的答案就是 f f f g g g的和了!

//班上某同学的代码,自己的代码太难解释了!
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>

using namespace std;

typedef long long ll;
const int maxn = 131072 + 10;
const int maxt = 32;

int n, m, t, dep[maxn + 5], len, maxlen;
ll f[maxn + 5][maxt + 5], g[maxn + 5][maxt + 5], a[maxn + 5], ans[maxn + 5][maxt + 5];

void dfs(int p) {
	if (p << 1 <= n) f[p][len] = f[p << 1][len - 1] + f[p << 1 | 1][len - 1];
	g[p][len] = g[p / 2][len - 1];
	if (len >= 2) g[p][len] += f[p ^ 1][len - 2];
	if ((p << 1) <= n) {
		dfs(p << 1);
		dfs(p << 1 | 1);
	}
}

int main() {
	int x, k;
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]); f[i][0] = g[i][0] = a[i];
		dep[i] = log2(i) + 1;
	}
	t = log2(n + 1); maxlen = t * 2 - 2;
	for (len = 1; len <= maxlen; len++) {
		dfs(1);
	}
	for (int i = 1; i <= m; i++) {
		scanf("%d %d", &x, &k);
		if (k > maxlen) printf("0\n");
		else printf("%lld\n", f[x][k] + g[x][k]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值