Solve this interesting problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1810 Accepted Submission(s): 542
Problem Description
Have you learned something about segment tree? If not, don’t worry, I will explain it for you.
Segment Tree is a kind of binary tree, it can be defined as this:
- For each node u in Segment Tree, u has two values: Lu and Ru .
- If Lu=Ru , u is a leaf node.
- If Lu≠Ru , u has two children x and y,with Lx=Lu , Rx=⌊Lu+Ru2⌋ , Ly=⌊Lu+Ru2⌋+1 , Ry=Ru .
Here is an example of segment tree to do range query of sum.
Given two integers L and R, Your task is to find the minimum non-negative n satisfy that: A Segment Tree with root node's value Lroot=0 and Rroot=n contains a node u with Lu=L and Ru=R .
Segment Tree is a kind of binary tree, it can be defined as this:
- For each node u in Segment Tree, u has two values: Lu and Ru .
- If Lu=Ru , u is a leaf node.
- If Lu≠Ru , u has two children x and y,with Lx=Lu , Rx=⌊Lu+Ru2⌋ , Ly=⌊Lu+Ru2⌋+1 , Ry=Ru .
Here is an example of segment tree to do range query of sum.
Given two integers L and R, Your task is to find the minimum non-negative n satisfy that: A Segment Tree with root node's value Lroot=0 and Rroot=n contains a node u with Lu=L and Ru=R .
Input
The input consists of several test cases.
Each test case contains two integers L and R, as described above.
0≤L≤R≤109
LR−L+1≤2015
Each test case contains two integers L and R, as described above.
0≤L≤R≤109
LR−L+1≤2015
Output
For each test, output one line contains one integer. If there is no such n, just output -1.
Sample Input
6 7 10 13 10 11
Sample Output
7 -1 12
题目大意:
给定一个区间[L,R],求根结点的右端点最少为多少,才可以满足区间[L,R]是这个线段树的一个结点。可以的话输出根结的右端点的最小值,不可以的话输出-1.
解题思路:
换个思路我们可以从下到上递归到根结点,也就是L = 0的时候递归结束,递归的时候一共可能出现四种情况,画图就可以知道,由于父结点是子节点区间长度的两倍,所以一直往上递归可以到根结点,每次更新区间中的右端点,就可以得出结果。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define inf 1e16
long long res; //全局变量统计最小值
long long m,n;
void dfs(long long ll,long long rr)
{
if(rr >= res || rr > 2 * n) //rr必须小于res才有更新的必要,父结点右端点不会超过两倍子结点右端点的值
return;
if(ll == 0) //到了根结点了
{
res = rr;
return;
}
long long temp = rr - ll + 1; //区间长度
if(ll - temp >= 0)
dfs(ll - temp,rr); //左区间扩大
if(ll - temp >= 1)
dfs(ll - temp - 1,rr); //左区间扩大
dfs(ll,rr+temp-1); //右区间扩大
dfs(ll,rr+temp); //右区间扩大
}
int main()
{
while(scanf("%lld%lld",&m,&n) != EOF)
{
res = inf; //初始很小
dfs(m,n); //左区间,右区间
if(res == inf) printf("-1\n");
else
printf("%lld\n",res);
}
return 0;
}