BZOJ4826: [Hnoi2017]影魔

来源:互联网 发布:尊龙长相知乎 编辑:程序博客网 时间:2024/04/28 00:26

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

Sample Output

30
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 wxh010910freopen( "data.in", "r", stdin );#endifn = 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 );}}


0 0