数据结构水题大赛 T1
XXX的面试
题面
题解
本题作为T1, 自然十分友好, 本题就是要求查询一个区间去掉极值的平均数. 有(20')的暴力得分, 可以用线段树得(60'), 正解是st表
20'暴力
这个不用说了, 直接几层循环套娃就能过
60'线段树
构造三棵线段树, 分别维护区间和, 区间最大值, 区间最小值, 每次查询三个值, 输出((区间和 - 区间最大值 - 区间最小值) / (区间长度 - 2))
单次查询时间复杂度 (O(logn))
100'st表
由于本题没有修改, 所以区间和可以用前缀和(O(n))预处理, (O(1))查询我在打标程的时候也没发现, 造数据的时候才发现能这样, 于是有了后4个测试点
区间最值可以用st表维护, 所以也可以(O(1))查询
AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
using namespace std;
int n, m, tr[10005], st[15][10005][2], A, B, two[10005];
bool flg;
double ans;
char ch;
string s;
inline void read(int &x)
{
int f=1;
x=0;
char s=getchar();
while(s<'0'||s>'9')
{
if(s=='-')
f=-1;
s=getchar();
}
while(s>='0'&&s<='9')
{
x=x*10+s-'0';
s=getchar();
}
x*=f;
}
inline void ask() {
read(A);
read(B);
ans = tr[B] - tr[A - 1];
int now = two[B - A + 1], ponow = 1 << now;
ans -= min(st[now][A][0], st[now][B - ponow + 1][0]);
ans -= max(st[now][A][1], st[now][B - ponow + 1][1]);
printf("%.4lf
", ans/(B - A - 1));
}
int main() {
read(n);
m = 0;
for (register int i(1); i <= n; ++i) {
if (i >= 1 << (m + 1)) {
two[i] = m + 1;
m++;
}
else {
two[i] = m;
}
read(A);
st[0][i][0] = A;
st[0][i][1] = A;
tr[i] = tr[i - 1] + A;//sum
}
for(register int i(2) , tmp(0); i <= n; i = i << 1, ++tmp) {
int j(1);
while (j + i <= n + 1) {
st[tmp + 1][j][0] = min(st[tmp][j][0], st[tmp][j + (i >> 1)][0]);//min
st[tmp + 1][j][1] = max(st[tmp][j][1], st[tmp][j + (i >> 1)][1]);//max
++j;
}
}
read(m);
for (register int i(1); i <= m; ++i) {
ask();
}
return 0;
}