Description
影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样
的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠
这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。
第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i<j)来说,若不存在 k[s](i
<s<j)大于 k[i]或者 k[j],则会为影魔提供 p1 的攻击力(可理解为:当 j=i+1 时,因为不存在满足 i<s<j 的 s,从
而 k[s]不存在,这时提供 p1 的攻击力;当 j>i+1 时,若max{k[s]|i<s<j}<=min{k[i],k[j]} , 则 提 供 p1 的 攻
击 力 ); 另 一 种 情 况 , 令 c 为k[i+1],k[i+2],k[i+3]......k[j-1]的最大值,若 c 满足:k[i]<c<k[j],或
者 k[j]<c<k[i],则会为影魔提供 p2 的攻击力,当这样的 c 不存在时,自然不会提供这 p2 的攻击力;其他情况的
点对,均不会为影魔提供攻击力。影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任
意一段区间[a,b],1<=a<b<=n,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑 所有满足a<=i<j<=b 的灵
魂对 i,j 提供的攻击力之和。顺带一提,灵魂的战斗力组成一个 1 到 n 的排列:k[1],k[2],...,k[n]。
Input
第一行 n,m,p1,p2
第二行 n 个数:k[1],k[2],...,k[n]
接下来 m 行,每行两个数 a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
1 <= n,m <= 200000;1 <= p1,p2 <= 1000
Output
共输出 m 行,每行一个答案,依次对应 m 个询问。
Sample Input
10 5 2 3
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
Sample Output
30
39
4
13
16
39
4
13
16
HINT
Source
主席树
首先第一种区间只有O(N)个,直接提取出来即可
第二种在两个值之间不好统计,可以考虑用<一边的减去第一种
然后推一推式子发现是个二维数点,维护3棵主席树即可
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define fill( x, y ) memset( x, y, sizeof x )
#define copy( x, y ) memcpy( x, y, sizeof x )
using namespace std;
typedef long long LL;
typedef pair < int, int > pa;
const int MAXN = 200020;
inline int read()
{
int sc = 0; char ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();
return sc;
}
int n, Q, p1, p2, a[MAXN], st[MAXN], top, tot;
struct Tree
{
int a[MAXN], mx[MAXN << 2], tot, L[MAXN], root[MAXN];
struct node
{
int ls, rs, cnt;
LL v1, v2;
}e[MAXN * 25];
inline void build(int x, int l, int r)
{
if( l == r ) { mx[ x ] = a[ l ]; return ; }
int mid = l + r >> 1;
build( x << 1, l, mid ); build( x << 1 | 1, mid + 1, r ); mx[ x ] = max( mx[ x << 1 ], mx[ x << 1 | 1 ] );
}
inline int querypos(int x, int l, int r, int p, int v)
{
if( mx[ x ] <= v ) return 0;
if( l == r ) return l;
int mid = l + r >> 1, ret;
if( mid <= p && ( ret = querypos( x << 1 | 1, mid + 1, r, p, v ) ) ) return ret;
return querypos( x << 1, l, mid, p, v );
}
inline void insert(int &x, int y, int l, int r, int p, int v1, int v2)
{
e[ x = ++tot ] = e[ y ];
e[ x ].v1 += v1; e[ x ].v2 += v2; e[ x ].cnt++;
if( l == r ) return ;
int mid = l + r >> 1;
if( p <= mid ) insert( e[ x ].ls, e[ y ].ls, l, mid, p, v1, v2 );
else insert( e[ x ].rs, e[ y ].rs, mid + 1, r, p, v1, v2 );
}
inline void solve()
{
build( 1, 1, n );
for( int i = 1 ; i <= n ; i++ )
{
L[ i ] = querypos( 1, 1, n, i - 1, a[ i ] ) + 1;
insert( root[ i ], root[ i - 1 ], 1, n, L[ i ], i, L[ i ] );
}
}
inline LL query(int x, int l, int r, int p)
{
if( !x ) return 0;
if( r <= p ) return e[ x ].v1 - 1LL * p * e[ x ].cnt;
if( l > p ) return e[ x ].v1 - e[ x ].v2;
int mid = l + r >> 1;
return query( e[ x ].ls, l, mid, p ) + query( e[ x ].rs, mid + 1, r, p );
}
}t1, t2;
struct info { int l, r; bool operator < ( const info &b ) const { return l < b.l; } } range[MAXN];
struct node { int ls, rs, v; } e[MAXN * 25];
int root[MAXN];
inline void insert(int &x, int y, int l, int r, int p)
{
e[ x = ++tot ] = e[ y ]; e[ x ].v++;
if( l == r ) return ;
int mid = l + r >> 1;
if( p <= mid ) insert( e[ x ].ls, e[ y ].ls, l, mid, p );
else insert( e[ x ].rs, e[ y ].rs, mid + 1, r, p );
}
inline int query(int x, int l, int r, int p)
{
if( !x || l >= p ) return 0;
if( r < p ) return e[ x ].v;
int mid = l + r >> 1;
return query( e[ x ].ls, l, mid, p ) + query( e[ x ].rs, mid + 1, r, p );
}
int main()
{
#ifdef wxh010910
freopen( "data.in", "r", stdin );
#endif
n = read(), Q = read(), p1 = read(), p2 = read();
for( int i = 1 ; i <= n ; i++ ) a[ i ] = read(), t1.a[ i ] = t2.a[ n - i + 1 ] = a[ i ];
t1.solve(); t2.solve();
for( int i = 1 ; i <= n ; i++ )
{
while( top && a[ st[ top ] ] < a[ i ] )
range[ st[ top-- ] ].r = i - 1;
st[ ++top ] = i;
}
while( top ) range[ st[ top-- ] ].r = n;
for( int i = n ; i ; i-- )
{
while( top && a[ st[ top ] ] < a[ i ] )
range[ st[ top-- ] ].l = i + 1;
st[ ++top ] = i;
}
while( top ) range[ st[ top-- ] ].l = 1;
sort( range + 1, range + n + 1 );
for( int i = n ; i ; i-- ) insert( root[ i ], root[ i + 1 ], 1, n, range[ i ].r );
while( Q-- )
{
int l = read(), r = read(), cnt = 0, L = 1, R = n, pos = n + 1;
LL cur = t1.query( t1.root[ r ], 1, n, l ) - t1.query( t1.root[ l - 1 ], 1, n, l );
l = n - l + 1, r = n - r + 1; swap( l, r );
cur += t2.query( t2.root[ r ], 1, n, l ) - t2.query( t2.root[ l - 1 ], 1, n, l );
cur *= p2;
l = n - l + 1, r = n - r + 1; swap( l, r );
while( L <= R )
{
int mid = L + R >> 1;
if( range[ mid ].l > l ) pos = mid, R = mid - 1;
else L = mid + 1;
}
cnt = r - l + query( root[ pos ], 1, n, r );
printf( "%lld\n", cur + 1LL * ( p1 - p2 ) * cnt );
}
}