Description:
小丫最近学习了线段树,但是由于她的智商比较低,运用的还不是很熟
练。于是小R给了她一点练习题训练,其中有一道是这样的。
这是小R写的线段树的一段建树代码:
只要调用buildtree(1,0,n)就可以得到一颗线段树了。显然,一颗线段树一
共有O(n)个节点,因为每一个节点都代表了一个不同的区间,所以线段树
上一共出现了O(n)个不同的区间。
现在小R给了你一个区间【l ;r 】 ,想要你告诉他一个最小的n使得区间【l ;】
出现在了用buildtree(1,0n)建出来的线段树中。
Input
第一行输入一个正整数丁表示数据组数。
接下来丁行每行三个整数L;R; lim表示一组询问,如果对于所有的0 <= n
<= lim都不存在满足条件的解,输出一1即可。
Output
对于每组询问输出一个答案。
Sample Input
2
0 5 10
6 7 10
Sample Output
5
7
这道题我没测,所以具体不知道是否能全过掉数据,但思路肯定是正确的。
你可以任意举一个0到n,画画所建出来的线段树,你会发现,这道题要求的不过是这个区间从哪里分出来,以此类推。
我们发现,对于任何一个子区间,分出它的母区间都有有四种可能((left-1)*2-right,right)(((left-1)*2-right+1,light)
(left,right*2-left),(left,right*2-left+1),于是就是一个搜索,当然不会超时.一些小细节啊,边界啊,自己去考虑,比较容易想到.
1 #include <iostream> 2 #include <fstream> 3 #include <cstdlib> 4 #include <cstring> 5 using namespace std; 6 7 ifstream fin("tree.in"); 8 ofstream fout("tree.out"); 9 10 int cnt_zu=0; 11 12 long long int dfs(int left,int right,int lim){ 13 if(left==0)return right; 14 if(right>lim)return lim+1; 15 int l=0,r=0; 16 long long ans=0x7fffffff; 17 l=(left-1)*2-right; 18 r=right; 19 if((r+l)/2==left-1)ans=min(ans,dfs(l,r,lim)); 20 if((r+l+1)/2==left-1)ans=min(ans,dfs(l+1,r,lim)); 21 l=left; 22 r=right*2-left; 23 if((r+l)/2==right)ans=min(ans,dfs(l,r,lim)); 24 if((r+l+1)==right)ans=min(ans,dfs(l,r+1,lim)); 25 return ans; 26 } 27 28 int main( ){ 29 fin>>cnt_zu; 30 for(int x=1;x<=cnt_zu;x++){ 31 int left=0,right=0; 32 int lim=0; 33 fin>>left>>right>>lim; 34 long long int ans=dfs(left,right,lim); 35 if(ans>lim)ans=-1; 36 cout<<ans<<endl; 37 fout<<ans<<endl; 38 } 39 return 0; 40 }
时间: 2024-10-13 02:35:37