Step1 Problem:
满二叉树,中序遍历按照1,2,3…给二叉树编号。
x点下一步只能到达 x+1点 或者 x-1点,花费时间为两个点之间路径的节点个数(不包含端点)。
求u点到v点所需时间。
数据范围:0 < u, v<=2^31-1。
Step2 Involving algorithms:
满二叉树 && dp
Step3 Ideas:
满二叉树的形状,左子树和右子树是一样的 且 对称。
我们预处理求出1->1, 1->2, 1->4, 1->8….所需的时间。
1->1 = 0, 因为不动
1->2 = 0, 因为之间路径节点个数为0
1->4 = 1->2 + 2->3 + 1 = 1;(1->2 = 2->3 因为以4为根的子树,它们是对称的。)
1->8 = 1->4 + 4->7 + 2 = 4;
1->16 = 1->8 + 8->15 + 3 = 11;
1->32 = 1->16 + 16->31 + 4 = 26; 以此类推下去。
状态dp[i]:1->(2^i)的时间,dp[i] = dp[i-1]*2+i-1;
假设我们求
1->12 = 1->8 + 8->9 + 1->4。
1->14 = 1->8 + 8->9 + 1->4 + 4->5 + 1->2。
Step4 Code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll dp[50];
ll solve(ll x)
{
int i;
ll res = 0;
while(1) {
// cout << res << ' ' << x << endl;
for(i = 0; ;i++)
{
if((1LL<<i) >= x) break;
}
if((1LL<<i) == x) {
return res + dp[i];
}
res += dp[i-1] + i-2;
x -= 1LL<<(i-1);
}
}
int main()
{
dp[0] = dp[1] = 0;
for(int i = 2; i <= 32; i++)//预处理1->(1<<i)所需的时间
{
dp[i] = dp[i-1]*2 + (i-1);
// cout << i << ' ' << dp[i] <<endl;
}
//cout << solve(12) << endl;
ll u, v;
while(cin >> u >> v)
{
if(u > v) swap(u, v);
cout << solve(v) - solve(u) << endl;
}
return 0;
}