HDU 5323 Solve this interesting problem DFS

题意

问最小的 n ,使得线段树0~n范围有一个节点的范围是包括恰好为L~R的!

分析:

其实这道题目大家多多少少会想到向上搜索所有的节点,但是其实就是一直DFS
关键就是 剪 枝 很重要!

对于 一个 LR L − R 的区间,我们有 4 4 种情况向父亲节点深搜:
1. [l,2rl] [ l , 2 ∗ r − l ]
2. [l,2r+1l] [ l , 2 ∗ r + 1 − l ]
3. [(l1)2r,r] [ ( l − 1 ) ∗ 2 − r , r ]
4. [(l1)2+1r,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
#include
#include 
#include
#include 
#define P pair
#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;
}

你可能感兴趣的:(总结,DFS,HDU)