您的位置:首页 > 其它

nyoj 1185 最大最小值 【线段树】

2015-11-16 11:59 351 查看


最大最小值

时间限制:1000 ms | 内存限制:65535 KB
难度:2

描述
给出N个整数,执行M次询问。
对于每次询问,首先输入三个整数C、L、R:

如果C等于1,输出第L个数到第R个数之间的最小值;

如果C等于2,输出第L个数到第R个数之间的最大值;

如果C等于3,输出第L个数到第R个数之间的最小值与最大值的和。
(包括第L个数和第R个数)。

输入首先输入一个整数T(T≤100),表示有T组数据。

对于每组数据,先输入一个整数N(1≤N≤10000),表示有N个整数;

接下来一行有N个整数a(1≤a≤10000);

然后输入一个整数M,表示有M次询问;

接下来有M行(1≤M≤10000),每行有3个整数C、L、R(1≤C≤3,1≤L≤R≤N)。
输出按照题意描述输出。每个输出占一行。
样例输入
2
4
1 3 2 4
2
1 1 4
2 2 3
5
1 2 3 4 5
1
3 1 5


样例输出
1
3
6


来源原创
上传者
TC_李远航

思路:

求最大值就需要建立最大树,求最小值就需要建立最小数,然后建立之后就只需要进行查找了,建立的时候可以同时建立两个树,但是当你查找的时候因为你的需要不同,所以你就需要写两个实现不同功能的函数,一个是实现求最大值的函数,也就是在最大树中找最大值,在最小树中找最小值,就OK了!

代码如下:

方法一:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
int tree1[40005];
int tree2[40005];
int c,l,r;
int min(int a,int b)
{
if(a>b)
return b;
return a;
}
int max(int a,int b)
{
if(a>b)
return a;
return b;
}
void build(int rt,int l,int r)
{
if(l==r)
{
scanf("%d",&tree1[rt]);
tree2[rt]=tree1[rt];
return;
}
int mid=(l+r)>>1,pt=rt<<1;
build(pt,l,mid);
build(pt|1,mid+1,r);
tree1[rt]=min(tree1[pt],tree1[pt|1]);
tree2[rt]=max(tree2[pt],tree2[pt|1]);
}
int find1(int rt,int l,int r,int a,int b)
{
if(l>=a&&r<=b)
{
return tree1[rt];
}
int mid=(l+r)>>1,pt=rt<<1,res=INF;
if(a<=mid)
{
res=min(find1(pt,l,mid,a,b),res);
}
if(b>mid)
{
res=min(find1(pt|1,mid+1,r,a,b),res);
}
return res;
}
int find2(int rt,int l,int r,int a,int b)
{
if(l>=a&&r<=b)
{
return tree2[rt];
}
int mid=(l+r)>>1,pt=rt<<1,res=-1;
if(a<=mid)
{
res=max(find2(pt,l,mid,a,b),res);//在它的左子树中找最小值
}//对应的数组的下标也是他的下标的2倍,pt代表的就是l到mid中的最小值
//如果满足l到mid在a,b的范围内说明找到最小值了,直接返回,将所有的a,b范围内的
//最小值都找到之后进行比较,输出最小的值!
if(b>mid)//这个是在右子树中找最小值
{//pt|1代表的是mid+1到r中的最小值,如果不在a,b区间里面,就继续递归,如果在a,b区间里面就直接返回最大值
res=max(find2(pt|1,mid+1,r,a,b),res);
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
build(1,1,n);
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&c,&l,&r);
if(c==1)
{
printf("%d\n",find1(1,1,n,l,r));
}
else if(c==2)
{
printf("%d\n",find2(1,1,n,l,r));
}
else if(c==3)
{
printf("%d\n",find1(1,1,n,l,r)+find2(1,1,n,l,r));
}
}
}
return 0;
}


方法二:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
int tree1[40005];
int tree2[40005];
int c,l,r;
int min(int a,int b)
{
if(a>b)
return b;
return a;
}
int max(int a,int b)
{
if(a>b)
return a;
return b;
}
void build(int rt,int l,int r)
{
if(l==r)
{
scanf("%d",&tree1[rt]);
tree2[rt]=tree1[rt];
return;
}
int mid=(l+r)>>1,pt=rt<<1;
build(pt,l,mid);
build(pt|1,mid+1,r);
tree1[rt]=min(tree1[pt],tree1[pt|1]);
tree2[rt]=max(tree2[pt],tree2[pt|1]);
}
int find1(int rt,int l,int r,int a,int b)
{//这个方法是要么在左子树里面查找,要么在右子树中查找,要么在左右子树中查找
//其实是一样的!
if(l>=a&&r<=b)
{
return tree1[rt];
}
int mid=(l+r)>>1,pt=rt<<1,res=INF;
if(b<=mid)
{
res=min(find1(pt,l,mid,a,b),res);
}
else if(a>mid)
{
res=min(find1(pt|1,mid+1,r,a,b),res);
}
else
{
res=min(find1(pt,l,mid,a,b),res);
res=min(find1(pt|1,mid+1,r,a,b),res);
}
return res;
}
int find2(int rt,int l,int r,int a,int b)
{
if(l>=a&&r<=b)
{
return tree2[rt];
}
int mid=(l+r)>>1,pt=rt<<1,res=-1;
if(b<=mid)
{
res=max(find2(pt,l,mid,a,b),res);
}
else if(a>mid)
{
res=max(find2(pt|1,mid+1,r,a,b),res);
}
else
{
res=max(find2(pt,l,mid,a,b),res);
res=max(find2(pt|1,mid+1,r,a,b),res);
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
build(1,1,n);
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&c,&l,&r);
if(c==1)
{
printf("%d\n",find1(1,1,n,l,r));
}
else if(c==2)
{
printf("%d\n",find2(1,1,n,l,r));
}
else
{
printf("%d\n",find1(1,1,n,l,r)+find2(1,1,n,l,r));
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: