题意
问最小的 n ,使得线段树0~n范围有一个节点的范围是包括恰好为L~R的!
分析:
其实这道题目大家多多少少会想到向上搜索所有的节点,但是其实就是一直DFS
关键就是 剪枝剪枝 很重要!
对于 一个 L−RL−R的区间,我们有 44种情况向父亲节点深搜:
1.
2.[l,2∗r+1−l][l,2∗r+1−l]
3.[(l−1)∗2−r,r][(l−1)∗2−r,r]
4.[(l−1)∗2+1−r,r][(l−1)∗2+1−r,r]
而且有剪枝就是这个:
if(ans != INF && R >= ans) return ;
//以为向上过程之中,这 4 种情况都是R区间只增不减!
关键就是这个顺序应该怎么搞,所以应该是往左边先搜,这样得出来的ans 才会有剪枝的价值,不然是会MLE,TLE 的!
于是顺序就是
4 3 2 1 这样DFS
代码:
#pragma GCC optimize(3)
#include<cstring>
#include<stdio.h>
#include <iostream>
#include<algorithm>
#include <vector>
#define P pair<int,int>
#define INF 0x3f3f3f3f
// #define MAXN = 20050-
#define ll long long
using namespace std;
ll L,R,ans;
void DFS(ll L,ll R)
{
if(L == 0) return (void)(ans = min(ans,R));
if(ans != INF && R >= ans) return ;
if(R < 0 || L<0) return ;
if(R-L+1 > (L-1) <<1 ) return ;
// 顺序是不能变的! 因为只有往左搜 R>=ans return 的剪枝才是有用的!
DFS(L,(R<<1) - L);
DFS(L,(R<<1) - L + 1);
DFS(((L-1)<<1) - R , R);
DFS(((L-1)<<1) - R +1 , R);
// L_ + R / 2 == L-1 ---> L_ = 2*(L-1) - R
}
int main()
{
while(~scanf("%lld%lld",&L,&R))
{
ans = INF;
DFS(L,R);
printf("%lld\n", (ans==INF)?-1:ans);
}
return 0;
}