二叉树如下:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ /
8 9 10
从最后一个节点n开始沿着父节点往上爬,直到1(上图中就是:10->5->2->1)。
重要的一点:如果当前节点有兄弟节点(例如:10没有兄弟,5的兄弟是4),那么这个兄弟节点(例如:4)代表的子树一定是个满二叉树。
基于此思想开始往上爬。 :)
/*
Title :Subtrees
Status:AC
By wf,
*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define FOR(i,s,t) for(int i = (s) ; i <= (t) ; ++i )
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
ll n;
set<ll>s;
ll insertnum(ll rt){
int c=0;
while( rt<=n )
{
c++;
s.insert( (1LL<<c)-1 );//把每一层的节点数加入集合
rt=(rt<<1)+1;
}
return ( (1LL<<c)-1 );//返回rt节点代表子树拥有的节点数
}
void up(ll rt,ll num,ll step){
s.insert(num);//把当前结点代表子树的节点数加入集合
//printf("insert::%d\n",num );
if(rt==1)return;
ll fa=rt/2;
bool left=1;//当前结点为父节点的左孩子
if(rt%2)left=0;
ll other=0;
if(left){
other = rt+1;
}else{
other = rt-1;
}
ll othernum=0;
if(other <= n) {
othernum = insertnum(other);
}
up(fa,num+othernum+1,step+1 );
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%lld",&n)!=EOF){
s.clear();
up(n,1,1);
printf("%d\n",s.size() );
}
return 0;
}