8.12 莫队

P3246 [HNOI2016] 序列

我们可以设置\(f[i]\)表示\(f[i] = f[pre[i]] + ( i - pre[i] ) * a[i]\)

其中\(pre[i]\)为这个点前一个严格小于\(a[i]\)的数的位置 用单调栈预处理即可

对于莫队的移动右端点操作 用\(st\)表查询区间最小值 那么计入答案就是\(( p - l + 1 ) * a[p] + f[r] - f[p]\)

对于移动左端点操作 完全相反地记录\(g,nxt[i]\)数组即可

需要\(long\ long\)

#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
#define int long long 
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}

int n , m , block , a[N] , lg[N] , f[N] , g[N] , pre[N] , nxt[N] , sta[N] , st[N][30] , top , res , ans[N];

struct que { int l , r , pos , id; } q[N];
inl int get ( int x , int y ) { return a[x] < a[y] ? x : y; }

void initsta ()
{
	top = 0 , sta[++top] = 0;
	for ( int i = 1 ; i <= n ; i ++ )
	{
		while ( top && a[sta[top]] >= a[i] ) top --;
		pre[i] = sta[top];
		sta[++top] = i;
	}
	top = 0 , sta[++top] = n + 1;
	for ( int i = n ; i ; i -- )
	{
		while ( top && a[sta[top]] >= a[i] ) top --;
		nxt[i] = sta[top];
		sta[++top] = i;
	}
	for ( int i = 1 ; i <= n ; i ++ ) f[i] = f[pre[i]] + ( i - pre[i] ) * a[i];
	for ( int i = n ; i >= 1 ; i -- ) g[i] = g[nxt[i]] + ( nxt[i] - i ) * a[i];
}

void initst ()
{
	lg[0] = -1;
	for ( int i = 1 ; i <= n ; i ++ ) lg[i] = lg[i>>1] + 1;
	for ( int i = 1 ; i <= n ; i ++ ) st[i][0] = i;
	for ( int j = 1 ; j <= lg[n] ; j ++ ) 
		for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
			st[i][j] = get ( st[i][j-1] , st[i+(1<<(j-1))][j-1] );
}

inl int query ( int l , int r ) { int len = lg[r-l+1]; return get ( st[l][len] , st[r-(1<<len)+1][len] ); }
inl int lft ( int l , int r ) { int p = query ( l , r ); return ( r - p + 1 ) * a[p] + g[l] - g[p]; }
inl int rgt ( int l , int r ) { int p = query ( l , r ); return ( p - l + 1 ) * a[p] + f[r] - f[p]; }

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = read() , m = read() , block = (int)sqrt(n);
	a[0] = a[n+1] = -inf;
	for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
	initsta() , initst();
	for ( int i = 1 ; i <= m ; i ++ ) q[i].l = read() , q[i].r = read() , q[i].id = i , q[i].pos = ( q[i].l - 1 ) / block + 1;
	sort ( q + 1 , q + m + 1 , [](const que &a , const que &b) { return a.pos == b.pos ? ( ( a.pos & 1 ) ? a.r < b.r : a.r > b.r ) : a.pos < b.pos; } );
	int l = 1 , r = 0;
	for ( int i = 1 ; i <= m ; i ++ )
	{
		while ( q[i].l < l ) res += lft ( -- l , r );
		while ( r < q[i].r ) res += rgt ( l , ++ r );
		while ( l < q[i].l ) res -= lft ( l ++ , r );
		while ( q[i].r < r ) res -= rgt ( l , r -- );
		ans[q[i].id] = res;
	}
	for ( int i = 1 ; i <= m ; i ++ ) cout << ans[i] << endl;
	return 0;
}

歴史の研究

因为\(del\)\(upd\)函数返回值写成了\(int\)而在\(atcoder\)上一直\(RE\)

而且暴力处理块的时候没写\(continue\)

#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
#define int long long 
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}

int n , m , lstblock , block , bel[N] , a[N] , ans[N] , bb[N] , b[N] , res , tot , ll[N] , rr[N];

struct node { int l , r , id; } q[N];

vector<int> lsh;
inl void add ( int x ) { res = max ( res , ( ++ b[x] ) * lsh[x] ); }
inl void del ( int x ) { -- b[x]; }

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = read() , m = read() , block = sqrt(n) , tot = n / block;
	if ( n % block ) tot ++;

	for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , lsh.eb(a[i]);
	sort ( lsh.begin() , lsh.end() );
	lsh.erase ( unique ( lsh.begin() , lsh.end() ) , lsh.end() );
	for ( int i = 1 ; i <= n ; i ++ ) a[i] = lower_bound ( lsh.begin() , lsh.end() , a[i] ) - lsh.begin();

	for ( int i = 1 ; i <= n ; i ++ ) bel[i] = ( i - 1 ) / block + 1;
	for ( int i = 1 ; i <= tot ; i ++ ) ll[i] = ( i - 1 ) * block + 1 , rr[i] = i * block; rr[tot] = n;

	for ( int i = 1 ; i <= m ; i ++ ) q[i].l = read() , q[i].r = read() , q[i].id = i;
	sort ( q + 1 , q + m + 1 , [](const node &a , const node &b) { return bel[a.l] == bel[b.l] ? a.r < b.r : bel[a.l] < bel[b.l]; } );
	
	int l = 1 , r = 0;
	for ( int i = 1 ; i <= m ; i ++ )
	{
		if ( bel[q[i].l] == bel[q[i].r] )
		{
			int temp = 0;
			for ( int j = q[i].l ; j <= q[i].r ; j ++ ) ++ bb[a[j]];
			for ( int j = q[i].l ; j <= q[i].r ; j ++ ) temp = max ( temp , bb[a[j]] * lsh[a[j]] );
			for ( int j = q[i].l ; j <= q[i].r ; j ++ ) -- bb[a[j]];
			ans[q[i].id] = temp;
			continue;
		}
		if ( bel[q[i].l] != lstblock )
		{
			while ( r < rr[bel[q[i].l]] ) add ( a[++r] );
			while ( rr[bel[q[i].l]] < r ) del ( a[r--] );
			while ( l < rr[bel[q[i].l]] + 1 ) del ( a[l++] );
			res = 0 , lstblock = bel[q[i].l];
		}
		while ( r < q[i].r ) add ( a[++r] );	
		int temp = res , templ = l;
		while ( q[i].l < templ ) add ( a[--templ] );
		while ( templ < l ) del ( a[templ++] );
		ans[q[i].id] = res;
		res = temp;
	}
	for ( int i = 1 ; i <= m ; i ++ ) cout << ans[i] << endl;
	return 0;
}
posted @ 2023-08-13 08:07  Echo_Long  阅读(7)  评论(0编辑  收藏  举报