1. 程式人生 > >YTU_3309: Lorenzo Von Matterhorn(完全二叉樹 最近公共祖先)

YTU_3309: Lorenzo Von Matterhorn(完全二叉樹 最近公共祖先)

3309: Lorenzo Von Matterhorn

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 6  解決: 6
[提交][狀態][討論版][命題人:acm4302]

題目描述

Barney住在紐約。紐約市有無限數量的路口,路口為從1開始編號的正整數。在路口i和2*i以及i和2*i +1之間存在雙向道路,您可以清楚地看到任意兩個路口之間存在唯一的最短路徑。 

最初任何人都可以免費通過所有道路。但是由於SlapsGiving領先於我們,很快就會有q個連續事件發生。有兩種型別的事件: 

1.政府制定新規則。規則可以用整數v,u和w表示。作為這一行動的結果,從u到v的最短路徑上的所有道路的通過費用增加了w美元。 

2. Barney從路口v移動到路口u那裡是他想擁抱的一個女孩。他總是使用兩個十字路口之間的最短路徑(訪問最小數量的交叉路口或道路)。 

政府需要你的計算。每次Barney去擁抱一個女孩時,他應該支付多少錢

輸入

輸入的第一行包含一個整數q(1≤q≤1 000)。

下面q行按時間順序包含有關事件的資訊。每個事件的形式描述 

1 v u w如果當政府提出一個新的規則有關從增加從u到v的最短路徑上的所有道路的通過費w美元。

2 v u當Barney從路口v到路口u擁抱一個女孩。

1≤v,u ≤10^18,v ≠ u,1≤ w ≤10^9

輸出

對於第二類事件,按相應事件的時間順序在一行中列印Barney道路的通行費總和。

樣例輸入

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

樣例輸出

94
0
32
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<k;i++)
#define per(i,j,k) for(int i=j;i<=k;i++)
#define IO ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
map <ll,ll> mp;

void swap(ll a, ll b)
{
   ll c;
   c=a;
   a=b;
   b=c;
}
void updateL(ll v,ll u ,ll w)
{
   while(v!=u)
   {
      if(v<u)
         swap(v,u);
      mp[v]+=w;
      v>>=1;
   }
}
void get_ans(ll v,ll u)
{
   ll ans = 0;
   while(v!=u)
   {
      if(v<u)
         swap(v,u);
      ans += mp[v];
      v>>=1;
   }
   cout<<ans<<endl;
}
int main(void)
{
   IO
   int n;cin>>n;
   ll v,u,w;
   int op;
   while(n--)
   {
      cin>>op;
      if(op&1)
      {
         cin>>v>>u>>w;
         updateL(v,u,w);
      }
      else
      {
         cin>>v>>u;
         get_ans(v,u);
      }
   }
}