数据结构水题大赛官方题解#1 XXX的面试

数据结构水题大赛 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;
}
原文地址:https://www.cnblogs.com/Wild-Donkey/p/13328525.html