#362(Div 2) C
题目大意: 有一颗无穷大的二叉树, 以编号1为的点根, 编号为i的点的儿子分别为i * 2, i * 2 + 1,
有q(1 <= q <= 1000)次操作:
1. 将点u到v的路径 上所有边的权值加w;
2. 查询u到v路径上边的权值和;
1 <= u, v <= 1018, w <= 109
题解
这题作为C题感觉有些水, 点数太多了, 而只有极少的点有用, 所以直接上map, 然后用类似LCA的方法直接搞一搞就行了。
#include <cstdio>
#include <map>
using namespace std;
typedef long long LL;
int log(LL x)
{
int l = 0;
while(x) x >>= 1, l ++;
return l;
}
map<LL, LL>m;
int main()
{
int q, ty, c;
LL a, b;
scanf("%d", &q);
for (int i = 1; i <= q; i ++) {
scanf("%d %I64d %I64d", &ty, &a, &b);
if (ty == 1) scanf("%d", &c);
int l1 = log(a), l2 = log(b);
LL sum = 0;
while(l1 > l2){
if (ty == 1) m[a] += c;
else sum += m[a];
a = a / 2, l1 --;
}
while(l1 < l2){
if (ty == 1) m[b] += c;
else sum += m[b];
b = b / 2, l2 --;
}
while(a != b){
if (ty == 1) m[a] += c, m[b] += c;
else sum += m[a] + m[b];
a = a / 2, b = b / 2;
}
if (ty == 2) printf("%I64d\n", sum);
}
return 0;
}