[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 lim2×1090LR109,T100,RL+1L2×103

题解

正着推是不行的,考虑从目标区间往回搜,直到搜到 l = 0 l=0 l=0的情况, DFS \text{DFS} DFS求出 r r r的最小值

4种扩展方案(下面设 [ l , r ] [l,r] [l,r]是当前区间):

  1. [ l , 2 r − l ] [l,2r-l] [l,2rl]
  2. [ l , 2 r − l + 1 ] [l,2r-l+1] [l,2rl+1]
  3. [ 2 l − r − 2 , r ] [2l-r-2,r] [2lr2,r]
  4. [ 2 l − r − 1 , r ] [2l-r-1,r] [2lr1,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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值