其他分享
首页 > 其他分享> > [JZOJ4208]「五校联考1day1」『DFS』线段树什么的最讨厌了

[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]是当前区间):

  1. [ l , 2 r − l ] [l,2r-l] [l,2r−l]
  2. [ l , 2 r − l + 1 ] [l,2r-l+1] [l,2r−l+1]
  3. [ 2 l − r − 2 , r ] [2l-r-2,r] [2l−r−2,r]
  4. [ 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