问题 C: 给你一个666

时间限制: 1 Sec  内存限制: 256 MB
提交: 342  解决: 60
[提交] [状态] [命题人:admin]

题目描述

Tongtong非常喜欢用“say 666”的方式来打招呼,因此热爱数学的他找到了一个说666的新方式。Tongtong构造了一个数学上很6的运算。定义一个6位二进制数上的运算 @ : a@b=(c,d)。其中 c = a的高3位*b的低3位 ; d = a的低3位*b的高3位。例如 010 001 @ 011 001 = (010*001 , 001*011) = (2*1,1*3) = (2,3) 。
Tongtong给出了两个操作数a和b。以及一个数列 x1,x2,x3 ... xn ,假设a@b的结果(c,d),Tongtong非常关心数列在区间 [ min(c,d)*min(a,b) ,max(c,d)*max(a,b) ]上的最小值和最大值,Tongtong认为上述区间上的最大值和最小值可以代表666的程度,所以每组操作数都要计算出这两个最值。由于时间紧迫,他需要你来帮助他完成这个工作。

 

输入

第一行输入两个正整数 n,q,分别表示数列数字的个数和询问个数.其中1<=n<=50 000,1<=q<=100 000。
第二行输入n个非负整数,表示数列中的元素x1,x2 ... xn, 每个元素都在int类型的范围内。
接下来q行,每行给出一对非负整数,a,b,其意义见题面。本题保证所有的a和b均为6位无符号整数。

 

 

输出

对于每个询问,输出一对整数,分别表示目标区间上的最大值和最小值.每个询问的结果单独占一行。
请不要输出多余的空行。

 

样例输入

复制样例数据

12 1
5 2 3 4 5 6 7 8 1 6 5 1
1 8

样例输出

8 2

 

提示

min(x,y)表示x和y的最小值, max(x,y)表示x和y的最大值.区间下标从1开始。
样例:
数列在区间[1,8]上的所有元素为{5 2 3 4 5 6 7 8},最大值为8,最小值为2。
若左边界越界则取1,若右边界越界则取n。

 

题意:中文题不解释

题解:就是求区间最大最小值,用到了线段树来优化,有一个巨坑的地方,看代码你会懂得~~(只要你被这个地方坑了)

上代码:

#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const int MAX = 1e5+10;
int a[MAX];
int man,mnn;
struct node{
    int minn,maxx,left,right;
}tree[MAX<<2];
void build(int k,int l,int r)//建立线段树
{
    tree[k].left=l;tree[k].right=r;
    tree[k].maxx=tree[k].minn=0;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(k<<1, l, mid);
    build(k<<1|1, mid+1, r);
} 
void update(int k,int pos,int height) //更新线段树
{
    int l=tree[k].left,r=tree[k].right;
    if(l==r){
        tree[k].maxx=tree[k].minn=height;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) update(k<<1, pos, height);
    else update( k<<1|1, pos, height);
    tree[k].maxx=max(tree[k<<1].maxx,tree[k<<1|1].maxx);
    tree[k].minn=min(tree[k<<1].minn,tree[k<<1|1].minn);
}
 
void conut(int k,int ll,int rr)//统计范围内最大值以及最小值
{
    int l=tree[k].left,r=tree[k].right;
    if(ll<=l&&rr>=r){
        man=max(man, tree[k].maxx);
        mnn=min(mnn,tree[k].minn);
        return;
    }
    int mid=(l+r)>>1;
    if(ll<=mid) conut(k<<1, ll, rr);
    if(rr>mid) conut(k<<1|1,ll, rr);
}
int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	build(1, 1, n);
	for (int i = 1; i <= n;i++){
		scanf("%d",&a[i]);
		update(1, i, a[i]);
	}
	while(k--){
		mnn=inf;
		man=0;
		int l,r;
		scanf("%d%d",&l,&r);
		int ls,rs;
		ls=l;
		rs=r;
		int cnt1=1;
		int cnt2=1;
		int ll[10],rr[10];
		int lz[10],rz[10];
		while(l){
			if(l%2) ll[cnt1++]=1;
			else ll[cnt1++]=0;
			l>>=1;
		}
		while(cnt1!=7){
			ll[cnt1++]=0;
		}
		for (int i = 6; i >= 1;i--){
			lz[6-i+1]=ll[i];
		}
		while(r){
			if(r%2) rr[cnt2++]=1;
			else rr[cnt2++]=0;
			r>>=1;
		}
		while(cnt2!=7){
			rr[cnt2++]=0;
		}
		for (int i = 6; i >= 1;i--){
			rz[6-i+1]=rr[i];
		}
		int x1,x2,y1,y2;
		x1=lz[1]*4+lz[2]*2+lz[3];
		x2=lz[4]*4+lz[5]*2+lz[6];
		y1=rz[1]*4+rz[2]*2+rz[3];
		y2=rz[4]*4+rz[5]*2+rz[6];
		int c,d;
		c=x1*y2;
		d=x2*y1;
		int minnl,maxxr; 
		minnl=min(c,d)*min(ls,rs);
		if(minnl<1||minnl>n) minnl=1;//巨坑位置
		maxxr=max(c,d)*max(ls,rs);
		if(maxxr>n||maxxr<1) maxxr=n;//巨坑位置
		conut(1,minnl,maxxr);
		printf("%d %d\n",man,mnn);
	}
	return 0;
}