传送门
这题比赛的时候虽然做的人相对较多,但是自己根本没有什么头绪。
一句话题意:\(n\)个数,\(m\)个询问,每次让你求
题解给了个线段树的乱七八糟的十分复杂的算法,没看懂。顾子哥给我推荐了一道几乎一模一样的题,洛谷上第一篇题解妙的很,所以直接看我的这篇题解吧。
那这道题就是要分别求一遍最大值和最小值罢了。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<queue>
#include<assert.h>
#include<ctime>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
#define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e5 + 5;
const int N = 18;
const ll mod = 1e9 + 7;
In ll read()
{
ll ans = 0;
char ch = getchar(), las = ' ';
while(!isdigit(ch)) las = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(las == '-') ans = -ans;
return ans;
}
In void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
In void MYFILE()
{
#ifndef mrclr
freopen("1005.in", "r", stdin);
freopen("ha.out", "w", stdout);
#endif
}
In ll ADD(ll a, ll b) {return a + b < mod ? a + b : a + b - mod;}
In ll quickpow(ll a, ll b)
{
ll ret = 1;
for(; b; b >>= 1, a = a * a % mod)
if(b & 1) ret = ret * a % mod;
return ret;
}
int n, m, a[maxn];
struct Node
{
ll f[maxn], sum[maxn];
}MIN[2], MAX[2];
int st[maxn], top = 0, pre[maxn];
In void calc(Node& A, int flg)
{
top = 0;
for(int i = n; i; --i)
{
while(top && a[i] <= a[st[top]]) pre[st[top--]] = i;
st[++top] = i;
}
while(top) pre[st[top--]] = 0;
for(int i = 1; i <= n; ++i) A.f[i] = ADD(A.f[pre[i]], 1LL * flg * a[i] * (i - pre[i]) % mod);
for(int i = 1; i <= n; ++i) A.sum[i] = ADD(A.sum[i - 1], A.f[i]);
}
int dp[maxn][N + 2][2], ha[maxn];
In void rmq_init()
{
for(int i = 1; i <= n; ++i) dp[i][0][0] = dp[i][0][1] = i;
for(int j = 1; (1 << j) <= n; ++j)
for(int i = 1; i + (1 << j) - 1 <= n; ++i)
{
int tp1 = dp[i][j - 1][0], tp2 = dp[i + (1 << (j - 1))][j - 1][0];
dp[i][j][0] = a[tp1] < a[tp2] ? tp1 : tp2;
tp1 = dp[i][j - 1][1], tp2 = dp[i + (1 << (j - 1))][j - 1][1];
dp[i][j][1] = a[tp1] > a[tp2] ? tp1 : tp2;
}
for(int i = 2; i <= n; ++i) ha[i] = ha[i >> 1] + 1;
}
#define pr pair<int, int>
#define F first
#define S second
In pr query(int L, int R)
{
int k = ha[R - L + 1];
int tp1 = dp[L][k][0], tp2 = dp[R - (1 << k) + 1][k][0];
int ret1 = a[tp1] < a[tp2] ? tp1 : tp2;
tp1 = dp[L][k][1], tp2 = dp[R - (1 << k) + 1][k][1];
int ret2 = a[tp1] > a[tp2] ? tp1 : tp2;
return make_pair(ret1, ret2);
}
In void solve()
{
calc(MIN[0], 1);
reverse(a + 1, a + n + 1);
calc(MIN[1], 1);
reverse(MIN[1].f + 1, MIN[1].f + n + 1);
reverse(MIN[1].sum + 1, MIN[1].sum + n + 1);
reverse(a + 1, a + n + 1);
for(int i = 1; i <= n; ++i) a[i] = -a[i];
calc(MAX[0], -1);
reverse(a + 1, a + n + 1);
calc(MAX[1], -1);
reverse(MAX[1].f + 1, MAX[1].f + n + 1);
reverse(MAX[1].sum + 1, MAX[1].sum + n + 1);
reverse(a + 1, a + n + 1);
for(int i = 1; i <= n; ++i) a[i] = -a[i];
rmq_init();
for(int i = 1; i <= m; ++i)
{
int L = read(), R = read(), len = R - L + 1;
pr tp = query(L, R); int p1 = tp.F, p2 = tp.S;
ll ans1 = MIN[0].sum[R] - MIN[0].sum[p1] - MIN[0].f[p1] * (R - p1) % mod;
ans1 = ADD(ans1 % mod, mod);
ll ans2 = MIN[1].sum[L] - MIN[1].sum[p1] - MIN[1].f[p1] * (p1 - L) % mod;
ans2 = ADD(ans2 % mod, mod);
ll ANS1 = ADD(1LL * a[p1] * (R - p1 + 1) % mod * (p1 - L + 1) % mod, ADD(ans1, ans2));
ans1 = MAX[0].sum[R] - MAX[0].sum[p2] - MAX[0].f[p2] * (R - p2) % mod;
ans1 = ADD(ans1 % mod, mod);
ans2 = MAX[1].sum[L] - MAX[1].sum[p2] - MAX[1].f[p2] * (p2 - L) % mod;
ans2 = ADD(ans2 % mod, mod);
ll ANS2 = ADD(1LL * a[p2] * (R - p2 + 1) % mod * (p2 - L + 1) % mod, ADD(ans1, ans2));
write(ADD(ANS1, ANS2) * quickpow(1LL * len * (len + 1) % mod, mod - 2) % mod), enter;
}
}
int main()
{
// MYFILE();
int T = read();
while(T--)
{
n = read(), m = read();
for(int i = 1; i <= n; ++i) a[i] = read();
solve();
}
return 0;
}