题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5323
题意:一个线段树所有叶子节点编号为0 ~ n,给出 l 和 r ,求出最小的n使得存在一个节点的左值等于l,右值等于r。
思路:根据[l, r]区间我们可以推出它的父亲节点区间的四种可能,即[(l-1)*2-r+1, r],[(l-1)*2-r, r],[(l-1)*2-r, r],[l, 2*r-l+1],[l, 2*r-l]。剪枝条件:当搜到的答案比已得的大(r > ans)则return,(l < 0)则return。该节点的区间长度即r - l + 1如果大于 l 则return, 原因:将(l,r)看做这个线段树的右子树的话,左子树的长度即为l,右子树的长度为(r - l + 1)线段树性质:左子树区间长度大于等于右子树的区间长度。
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int ans;
void dfs(int l, int r)
{
if(r >= ans || l < 0) return;
if(l == 0)
{
ans = r;
return;
}
if(r - l + 1 > l) return ;
dfs((l-1)*2-r+1, r);
dfs((l-1)*2-r, r);
dfs(l, 2*r-l+1);
dfs(l, 2*r-l);
}
int main()
{
int l, r;
while(~scanf("%d%d",&l,&r))
{
ans = inf;
dfs(l, r);
if(ans == inf) printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}