老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题。
输入格式:
输入中第一行有两个数m,n表示有m(m<=100000)笔账,n表示有n个问题,n<=100000。
第二行为m个数,分别是账目的钱数
后面n行分别是n个问题,每行有2个数字说明开始结束的账目编号。
输出格式:
输出文件中为每个问题的答案。具体查看样例。
2 3 1
(这个题也可以用线段树做(同样非常简单),但练习分块所以整理一下。)
首先,将长度为n的序列分割成√n个块。维护每一个块内的最小值
查询一段区间的时候,先跑两段暴力:
1、x到x所属区间的右端点。
2、y所属区间的左端点到y
再枚举x和y之间的块已经维护出来的最小值
#include <bits/stdc++.h> #define ll long long using namespace std; inline void read(ll &a) { a=0;int c=getchar(); while(c>‘9‘||c<‘0‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) a=(a<<3)+(a<<1)+c-48,c=getchar(); } const int N=1e5+5; ll n,m,minx[N],block,a[N],bl[N],l,r; inline ll query(ll l,ll r) { ll ans=0x7fffff; for(int i=l;i<=min(bl[l]*block,r);i++) ans=min(a[i],ans); if(bl[l]!=bl[r]) { for(int i=(bl[r]-1)*block+1;i<=r;i++) ans=min(a[i],ans); } for(int i=bl[l]+1;i<bl[r];i++) ans=min(minx[i],ans); return ans; } int main() { memset(minx,0x7f,sizeof(minx)); read(n);read(m); for(int i=1;i<=n;i++) read(a[i]); block=sqrt(n); for(int i=1;i<=n;i++) { bl[i]=(i-1)/block+1; minx[bl[i]]=min(minx[bl[i]],a[i]); } while(m--) { read(l);read(r); cout<<query(l,r)<<‘ ‘; } }
原文:https://www.cnblogs.com/chu-xuan/p/10088884.html