[JZOJ4208]「五校联考1day1」『DFS』线段树什么的最讨厌了
作者:互联网
题目
小Y 最近学习了线段树,但是由于她的智商比较低,运用的还不是很熟练。于是小R 给了她一点练习题训练,其中有一道是这样的。
这是小R 写的线段树的一段建树代码:
只要调用buildtree(1,0,n) 就可以得到一颗线段树了。显然,一颗线段树一共有O(n) 个节点,因为每一个节点都代表了一个不同的区间,所以线段树上一共出现了O(n) 个不同的区间。
现在小R 给了你一个区间
[
l
,
r
]
[l,r]
[l,r],他想要你告诉他一个最小的n使得区间
[
l
,
r
]
[l,r]
[l,r] 出现在了用buildtree(1,0,n) 建出来的线段树中,如果对于所有的0
≤
\le
≤n
≤
\le
≤lim 都不存在满足条件的解,输出-1即可。
l i m ≤ 2 × 1 0 9 , 0 ≤ L ≤ R ≤ 1 0 9 , T ≤ 100 , L R − L + 1 ≤ 2 × 1 0 3 lim\le2\times 10^9,0\le L\le R\le 10^9,T\le 100,\frac{L}{R-L+1}\le2\times 10^3 lim≤2×109,0≤L≤R≤109,T≤100,R−L+1L≤2×103
题解
正着推是不行的,考虑从目标区间往回搜,直到搜到 l = 0 l=0 l=0的情况, DFS \text{DFS} DFS求出 r r r的最小值
4种扩展方案(下面设 [ l , r ] [l,r] [l,r]是当前区间):
- [ l , 2 r − l ] [l,2r-l] [l,2r−l]
- [ l , 2 r − l + 1 ] [l,2r-l+1] [l,2r−l+1]
- [ 2 l − r − 2 , r ] [2l-r-2,r] [2l−r−2,r]
- [ 2 l − r − 1 , r ] [2l-r-1,r] [2l−r−1,r]
如果单单这样做,时间复杂度将不足以通过此题,所以要考虑剪枝
剪枝1:非法剪枝
将非法的情况剪掉,如 r > l i m r>lim r>lim或者 l < 0 l<0 l<0
剪枝2:最优答案剪枝
如果当前的 r r r已经大于答案 a n s ans ans,说明此时不会对答案造成影响,剪去
剪枝3:不存在剪枝(关键)
当 2 l < r 2l<r 2l<r的时候,这个区间在线段树上是不会存在的,剪掉
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll t,l,r,mx,ans;
void dg(ll l,ll r)
{
if (l<0) return;
if (r>mx) return;
if (r>=ans) return;
if (l==0)
{
ans=min(ans,r);
return;
}
if (2*l<r) return;
if (2*r-l>l) dg(l,2*r-l);
if (2*l-r-2<r) dg(2*l-r-2,r);
if (2*r-l+1>l) dg(l,2*r-l+1);
if (2*l-r-1<r) dg(2*l-r-1,r);
}
int main()
{
scanf("%lld",&t);
while (t--)
{
scanf("%lld%lld%lld",&l,&r,&mx);
ans=mx+1;
dg(l,r);
if (ans==mx+1) printf("-1\n");
else printf("%lld\n",ans);
}
return 0;
}
标签:剪枝,le,ll,线段,1day1,JZOJ4208,ans,2l,联考 来源: https://blog.csdn.net/LZX_lzx/article/details/115417811