题目链接:http://codeforces.com/contest/697/problem/C
题意:有1~n的n个点,对于第i个点它的2*i与2*i+1有一条无向的边。现在有两种操最,第一种是将从u到v的最短路径上所有边的 权值加上w。第二种是询问u到v最短路劲上的花费是多少。
解法:我们可以将从1开始将所有的边画出来,不难发现这就是一棵二叉树。他们的最短路径即为他们到公共父亲的距离。然后我们可以不断的将u,v中最大的除以二。我们就可以求出u,v最短路径所经过的点。u==v时,这就是他们的公共父亲。对于询问也可以同样处理。由于u,v超int了,我们可以用到map来映射。map[]映射的初始化默认值为0.
AC:
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define ll __int64
map<pair<ll,ll> ,ll> m;
ll q,u,v,w,t;
pair<ll,ll>tt;
void print()
{
cout<<tt.first<<" "<<tt.second<<" "<<m[tt]<<endl;
}
#include<iostream>
#include<cmath>
#include<map>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define ll __int64
map<pair<ll,ll> ,ll> m;
ll q,u,v,w,t;
pair<ll,ll>tt;
void print()
{
cout<<tt.first<<" "<<tt.second<<" "<<m[tt]<<endl;
}
int main()
{
//freopen("in.txt","r",stdin);
{
//freopen("in.txt","r",stdin);
m.clear();
scanf("%I64d",&q);
while(q--)
{
scanf("%I64d",&t);
if(t==1)
{
scanf("%I64d%I64d%I64d",&u,&v,&w);
scanf("%I64d",&q);
while(q--)
{
scanf("%I64d",&t);
if(t==1)
{
scanf("%I64d%I64d%I64d",&u,&v,&w);
while(u!=v)
{
if(u>v)
{
{
if(u>v)
{
tt=make_pair(u,u/2);
m[tt]+=w;
u=u/2;
}
else if(u<v)
{
m[tt]+=w;
u=u/2;
}
else if(u<v)
{
tt=make_pair(v,v/2);
m[tt]+=w;
v=v/2;
}
// print();
}
}
else
{
scanf("%I64d%I64d",&u,&v);
ll ans=0;
while(u!=v)
{
if(u>v)
{
tt=make_pair(u,u/2);
ans+=m[tt];
u=u/2;
}
else if(u<v)
{
m[tt]+=w;
v=v/2;
}
// print();
}
}
else
{
scanf("%I64d%I64d",&u,&v);
ll ans=0;
while(u!=v)
{
if(u>v)
{
tt=make_pair(u,u/2);
ans+=m[tt];
u=u/2;
}
else if(u<v)
{
tt=make_pair(v,v/2);
ans+=m[tt];
v=v/2;
}
//print();
}
printf("%I64d\n",ans);
}
}
ans+=m[tt];
v=v/2;
}
//print();
}
printf("%I64d\n",ans);
}
}
}