【RMQ】或【线段树】 题目:【Usaco2007 Jan Balanced Lineup排队】 或【飞盘比赛】
本人水平有限,题解不到为处,请多多谅解
本蒟蒻谢谢大家观看
题目:传送门
Problem E: 飞盘比赛
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 176 Solved: 126
[Submit][Status][Web Board]
Description
每天, Cici 的N(1 <= N <= 50,000)头学生排成一行. 有一天, Cici 决定让一些学生们玩一场飞盘比赛. 他准备
找一群在对列中为置连续的学生来进行比赛. 但是为了避免比赛没有悬念,学生的身高不应该相差太大. Cici 准备
了Q (1 <= Q <= 180,000) 个可能的学生的选择和所有学生的身高 (1 <= 身高 <= 1,000,000). 他想知道每一组
里面最高和最低的学生的身高差别. 注意: 在最大数据上, 输入和输出将占用大部分运行时间.
找一群在对列中为置连续的学生来进行比赛. 但是为了避免比赛没有悬念,学生的身高不应该相差太大. Cici 准备
了Q (1 <= Q <= 180,000) 个可能的学生的选择和所有学生的身高 (1 <= 身高 <= 1,000,000). 他想知道每一组
里面最高和最低的学生的身高差别. 注意: 在最大数据上, 输入和输出将占用大部分运行时间.
Input
* 第一行: N 和 Q. * 第2..N+1行: 第i+1行是第i个学生的身高.
* 第N+2..N+Q+1行: 两个整数, A 和 B (1 <= A <= B <= N), 表示从A到B的所有学生.
* 第N+2..N+Q+1行: 两个整数, A 和 B (1 <= A <= B <= N), 表示从A到B的所有学生.
Output
*第1..Q行: 所有询问的回答 (最高和最低的学生的身高差), 每行一个.
Sample Input
6 3
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output
6
3
0
HINT
RMQ模板 或 线段树模板
code:
法一:RMQ
#include<bits/stdc++.h> #pragma GCC optimize(3) using namespace std; int n,Q; int a[180001]; int l,r,ans; int f[180001][21],g[180001][21],len[180001]; //f 取最大值, g 取最小值 //因为 2^21=2097152 > 180001 所以第二维只需要取到21 inline int read(){ int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')f=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } //RMQ的初始化过程 (建树) void build(){ for(int i=1;i<=n;i++){ f[i][0]=a[i];//本身最大值为本身 g[i][0]=a[i];//同理 :最小值也为本身 } len[0]=1; for(int i=1;i<=21;i++) len[i]=len[i-1]*2;//计算2^x 预处理 for(int i=n;i>=1;i--){//必须写逆循环 因为下面 j== 1~2^1+n-1 …… for(int j=1;len[j]+i-1<=n;j++){// 求区间 i~i+2^j-1 f[i][j]=max(f[i][j-1],f[i+len[j-1]][j-1]); g[i][j]=min(g[i][j-1],g[i+len[j-1]][j-1]); //i~i+2^(j-1)-1 与 i+2^(j-1)~i+2^(j-1)+2^(j-1)-1 //即:i~i+2^j-1 } } return ; } //RMQ查询过程 int query(int x,int y){ int k=log2(y-x+1);//求区间x~y 满足 2^k<=y-x+1,并且使 k 最大 int maxx=max(f[x][k],f[y-(1<<k)+1][k]); int minn=min(g[x][k],g[y-(1<<k)+1][k]); //当 x=1 , y=9 时,k=3; //f[x][k] →(x) ~ (x)+(2^k-1) 如:1~8; //f[y-(1<<k)+1][k] →(y-2^k+1) ~ (y-2^k+1)+(2^k-1) 如:2~9; //在 (1~8 的最值) 与 (2~9 的最值) 之间比较即可 return maxx-minn; } int main(){ n=read();Q=read(); for(int i=1;i<=n;i++) a[i]=read(); build(); for(int i=1;i<=Q;i++){ l=read(),r=read(); ans=query(l,r); printf("%d\n",ans); } return 0; }
code:
法二:线段树
#pragma GCC optimize(3) #include<bits/stdc++.h> #define maxn 100000 using namespace std; int n,m,k,x,y; int a[maxn]; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch<='9'&&ch>='0') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } struct segment { int sum[4*maxn],sum2[4*maxn],ans1,ans2; segment() { memset(sum,-63,sizeof(sum)); memset(sum2,-63,sizeof(sum2)); } #define lson (p+p) #define rson (p+p+1) void update(int p) { sum[p]=max(sum[lson],sum[rson]); sum2[p]=min(sum2[lson],sum2[rson]); }//求和 void build(int p,int l,int r) { if(l==r) { sum[p]=a[l]; sum2[p]=a[l]; return; } int mid=(l+r)/2; build(lson,l,mid); build(rson,mid+1,r); update(p); } void change(int p,int l,int r,int x,int v) { if(l==r&&x==l) { sum[p]+=v; return; } int mid=(l+r)/2; if(x<=mid)change(lson,l,mid,x,v); if(x>mid)change(rson,mid+1,r,x,v); update(p); }//把a[x]修改成v int querymax(int p,int l,int r,int x,int y) { if(x<=l&&r<=y) { return sum[p]; } int mid=(l+r)/2,ans1=-1e9; if(x<=l&&y>=r)return ans1=max(ans1,sum[p]); if(x<=mid)ans1=max(ans1,querymax(lson,l,mid,x,y)); if(y>mid)ans1=max(ans1,querymax(rson,mid+1,r,x,y)); update(p); return ans1; }//查询x,y区间和 int querymin(int p,int l,int r,int x,int y) { if(x<=l&&r<=y) { return sum2[p]; } int mid=(l+r)/2,ans2=1e9; if(x<=l&&y>=r)return ans2=min(ans2,sum2[p]); if(x<=mid)ans2=min(ans2,querymin(lson,l,mid,x,y)); if(y>mid)ans2=min(ans2,querymin(rson,mid+1,r,x,y)); update(p); return ans2; }//查询x,y区间和 }kd; int main() { n=read(); m=read(); for(int i=1;i<=n;i++)a[i]=read(); kd.build(1,1,n); for(int i=1,a,b;i<=m;i++) { a=read(); b=read(); printf("%d\n",kd.querymax(1,1,n,a,b)-kd.querymin(1,1,n,a,b)); } return 0; }
其实RMQ数据结构类似于线段树
只需要使用一些特殊值方法,基本上可以理解