Codeforces697C Lorenzo Von Matterhorn

2023-12-28 01:09

本文主要是介绍Codeforces697C Lorenzo Von Matterhorn,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Lorenzo Von Matterhorn

Barney lives in NYC. NYC has infinite number of intersections numbered with positive integers starting from 1. There exists a bidirectional road between intersections i and 2i and another road between i and 2i + 1 for every positive integer i. You can clearly see that there exists a unique shortest path between any two intersections.

Initially anyone can pass any road for free. But since SlapsGiving is ahead of us, there will q consecutive events happen soon. There are two types of events:

1. Government makes a new rule. A rule can be denoted by integers vu and w. As the result of this action, the passing fee of all roads on the shortest path from u to v increases by w dollars.

2. Barney starts moving from some intersection v and goes to intersection u where there's a girl he wants to cuddle (using his fake name Lorenzo Von Matterhorn). He always uses the shortest path (visiting minimum number of intersections or roads) between two intersections.

Government needs your calculations. For each time Barney goes to cuddle a girl, you need to tell the government how much money he should pay (sum of passing fee of all roads he passes).

Input

The first line of input contains a single integer q (1 ≤ q ≤ 1 000).

The next q lines contain the information about the events in chronological order. Each event is described in form 1 v u w if it's an event when government makes a new rule about increasing the passing fee of all roads on the shortest path from u to v by w dollars, or in form 2 v u if it's an event when Barnie goes to cuddle from the intersection v to the intersection u.

1 ≤ v, u ≤ 1018, v ≠ u, 1 ≤ w ≤ 109 states for every description line.

Output

For each event of second type print the sum of passing fee of all roads Barney passes in this event, in one line. Print the answers in chronological order of corresponding events.

Example

input
7
1 3 4 30
1 4 1 2
1 3 6 8
2 4 3
1 6 1 40
2 3 7
2 2 4
output
94
0
32

题意:有一棵无限多的满二叉树,根结点的值为1,两个子结点的数分别为两倍的根结点和两倍的根结点加一。

一开始每条边的权值均为0。

现在有两种操作,操作1是将两个结点之间所有路径的边权值加w。

操作2是给你两个结点为要你求出两结点的路径长度。

解法:暴力

由于树的特性,其实每次的更新或是查找相关的结点并不多。所以可以用一个map<pair, int>存储每两个结点间的权值。

对于两个数要想找到他们的路径,我们首先需要找到两者的最近公共祖先,其实就是二进制位高位相等的位数。

比如对于数6和5 二进制分别为110和101那么1就是两者的lca,首先需要把5->2->1的权值更新,再更新1->3->6。

于是从高到低比较两者的二进制,然后先向lca更新,再向下更新。

由于数据量不大,用map暴力就可以。就是编码可能有一些些复杂。

#include <bits/stdc++.h>
#include <cstdio>
#define ll long long
#define __max(a,b) a > b ? a : b
#define pll pair<ll, ll>
using namespace std;
const int maxn = 1e5 + 10;
map<pll, ll> power;
int U[100], V[100];
ll f, u, v, w;
int main()
{
//    freopen("/Users/vector/Desktop/out.txt", "w", stdout);ios::sync_with_stdio(false);cin.tie(0);int q;cin >> q;while(q--){cin >> f >> u >> v;if(f == 1) cin >> w;if(u > v)swap(u, v);int iu = 0, iv = 0;ll uu = u, vv = v;while(uu > 0){U[iu++] = uu % 2;uu /= 2;}while(vv > 0){V[iv++] = vv % 2;vv /= 2;}int i;for(i = 0; i < iu; i++){if(U[iu - i - 1] != V[iv - i - 1])break;}if(f == 1){if(i < iu)//向上更新{for(int j = i; j <= iu - 1; j++){power[make_pair(u, u / 2)] += w;power[make_pair(u / 2, u)] += w;//注意每次要记得双向更新u /= 2;}}for(int j = i; j < iv; j++)//向下更新{if(V[iv - j - 1]){power[make_pair(u, (u << 1) + 1)] += w;power[make_pair(u * 2 + 1, u)] += w;u = (u << 1)+ 1;}else{power[make_pair(u, u << 1)] += w;power[make_pair(u << 1, u)] += w;u = u << 1;}}}else//查询两点间路径时也类似{ll ans = 0;if(i < iu){for(int j = i; j <= iu - 1; j++){ans += power[make_pair(u, u / 2)];u /= 2;}}for(int j = i; j < iv; j++){if(V[iv - j - 1]){ans += power[make_pair(u, (u << 1) + 1)];u = (u << 1)+ 1;}else{ans += power[make_pair(u, u << 1)];u = u << 1;}}cout << ans << endl;}}return 0;
}

事实上,这样写还是写麻烦了。

更好的办法是,由于从子结点向父结点就只有一条路径。所以可以直接用map存每个结点到父结点的权值。

每次两个值循环向上找公共祖先。( 大的数不断的除以2)

这样的代码就很elegant了。

#include <bits/stdc++.h>
#include <cstdio>
#define ll long long
#define __max(a,b) a > b ? a : b
#define pll pair<ll, ll>
using namespace std;
const int maxn = 1e5 + 10;
map<ll, ll> power;
bool U[100], V[100];
ll f, u, v, w;
int main()
{//    freopen("/Users/vector/Desktop/out.txt", "w", stdout);ios::sync_with_stdio(false);cin.tie(0);int q;cin >> q;while(q--){cin >> f >> u >> v;if(f == 1) cin >> w;if(u > v)swap(u, v);if(f == 1){while(u != v){if(u > v)swap(u, v);power[v] += w;v /= 2;}}else{ll ans = 0;while(u != v){if(u > v)swap(u, v);ans += power[v];v /= 2;}cout << ans << endl;}}return 0;
}

 

这篇关于Codeforces697C Lorenzo Von Matterhorn的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/544748

相关文章

von Mises-Fisher Distribution (代码解析)

torch.distribution 中包含了很多概率分布的实现,本文首先通过均匀分布来说明 Distribution 的具体用法, 然后再解释 von Mises-Fisher 分布的实现, 其公式推导见 von Mises-Fisher Distribution. 1. torch.distribution.Distribution 以下是 Uniform 的源码: class Unif

冯米塞斯应力(von Mises stress)云图的MATLAB计算方法

关注 M r . m a t e r i a l   , \color{Violet} \rm Mr.material\ , Mr.material

区分RISC,CISC,Harvard architecture,Von_Neumann_architecture

指令集分类: RISC(Riduced Instruction Set Computer)精简指令集计算机 CISC(Complex Instruction Set Computer)复杂指令集计算机 存储器结构分类: 冯·诺伊曼结构(von Neumann architecture)又称为普林斯顿结构这种体系结构采用程序代码存储器与数据存储器合并在同一存储器里,但程序

cpu arch之risc, cisc ,von-neumann,harvard ,modified harvard

risc设计规范 The best way to understand RISC is to treat it as a concept to design processors. Although initial RISC processors had fewer instructions compared to their CISC counterparts, the new gener

Bernstein–von Mises类型的定理

Bernstein–von Mises类型的定理 符号前言贝叶斯公式泰勒展开 Bernstein–von Mises类型的定理渐进理论总结参考文献 Bernstein–von Mises类型的定理指出,可用于采样的数据越多,先验概率对预测模型的影响就越小,至少对于具有特定约束集的常见贝叶斯推理模型是这样。随着数据池的扩大,后验分布变得更加独立于先验概率假设,后验曲线看起来就