\(\mathcal{Description}\)

  Link.

  给定序列 \(\{a_n\}\),和 \(q\) 次形如 \([L,R]\) 的询问,每次回答

\[\sum_{[l,r]\subseteq [L,R]}\min_{i=l}^r\{a_i\}\cdot\max_{i=l}^r\{a_i\}\pmod{10^9+7}.
\]

  \(n,q\le10^5\)。

\(\mathcal{Solution}\)

  瞬间联想到 这道题,尝试把询问挂到猫树上分治处理。对于分治区间 \([l,r]\),令其中点为 \(p\),考虑离线处理挂在它身上的询问。

  而此时,我们需要用扫描线进行进一步转化:左端点 \(i\) 从 \(p\) 向 \(l\) 扫描,维护 \(j=p+1..r\) 的答案。考虑 \(i\) 确定时,\(j\in(p,r]\) 形成的 \([i,j]\) 的权值有以下四种:

  • 最小值、最大值在 \([i,p]\);
  • 最小值在 \([i,p]\),最大值在 \((p,r]\);
  • 最大值在 \([i,p]\),最小值在 \((p,r]\);
  • 最小值、最大值在 \((p,r]\)。

  简直和上面那题一模一样呢。发现贡献无非是左边的最小/最大值等形式的系数乘上右边相同形式的系数,询问时即求右边贡献的前缀和。可以用四科线段树维护四种类型的贡献。复杂度 \(\mathcal O((q+n\log n)\log n)\)。

  Ummm... 有 \(\mathcal O(n\log n)\) 的做法,大概是只用扫描线,然后矩阵线段树维护历史和,见 祂的博客

\(\mathcal{Code}\)

/*~Rainybunny~*/

#include <bits/stdc++.h>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
? EOF : *p++;
} inline int rint() {
int x = 0, s = fgc();
for ( ; s < '0' || '9' < s; s = fgc() );
for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
return x;
} inline void wint( const int x ) {
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
} const int MAXN = 1e5, MOD = 1e9 + 7;
int n, q, a[MAXN + 5], ans[MAXN + 5]; inline int imin( const int u, const int v ) { return u < v ? u : v; }
inline int imax( const int u, const int v ) { return u < v ? v : u; }
inline int mul( const int u, const int v ) { return 1ll * u * v % MOD; }
inline int add( int u, const int v ) { return ( u += v ) < MOD ? u : u - MOD; }
inline void addeq( int& u, const int v ) { ( u += v ) >= MOD && ( u -= MOD ); } struct Atom {
int l, r, id;
inline bool operator < ( const Atom& t ) const { return l < t.l; }
};
std::vector<Atom> qbuc[MAXN << 2];
int all[MAXN << 2]; inline void hang( const int u, const int l, const int r,
const int ql, const int qr, const int qid ) {
if ( ql <= l && r <= qr ) return qbuc[u].push_back( { l, r, qid } );
int mid = l + r >> 1;
if ( qr <= mid ) hang( u << 1, l, mid, ql, qr, qid );
else if ( mid < ql ) hang( u << 1 | 1, mid + 1, r, ql, qr, qid );
else {
qbuc[u].push_back( { ql, qr, qid } );
hang( u << 1, l, mid, ql, mid, qid );
hang( u << 1 | 1, mid + 1, r, mid + 1, qr, qid );
}
} struct SegmentTree { // how to replace it with BIT?
int sum[MAXN << 2], coe[MAXN << 2], tag[MAXN << 2]; inline void pushad( const int u, const int v ) {
addeq( tag[u], v ), addeq( sum[u], mul( coe[u], v ) );
} inline void pushdn( const int u ) {
if ( tag[u] ) {
pushad( u << 1, tag[u] ), pushad( u << 1 | 1, tag[u] );
tag[u] = 0;
}
} inline void pushup( const int u ) {
sum[u] = add( sum[u << 1], sum[u << 1 | 1] );
} inline void build( const int u, const int l, const int r, const int* c ) {
sum[u] = tag[u] = 0;
if ( l == r ) return void( coe[u] = c == NULL ? 1 : c[l] );
int mid = l + r >> 1;
build( u << 1, l, mid, c ), build( u << 1 | 1, mid + 1, r, c );
coe[u] = add( coe[u << 1], coe[u << 1 | 1] );
} inline void modify( const int u, const int l, const int r,
const int ml, const int mr, const int v ) {
// if ( l > r ) return ; // well, I'll promise it.
if ( ml <= l && r <= mr ) return pushad( u, v );
int mid = l + r >> 1; pushdn( u );
if ( ml <= mid ) modify( u << 1, l, mid, ml, mr, v );
if ( mid < mr ) modify( u << 1 | 1, mid + 1, r, ml, mr, v );
pushup( u );
} inline int query( const int u, const int l, const int r,
const int ql, const int qr ) {
if ( ql <= l && r <= qr ) return sum[u];
int mid = l + r >> 1, ret = 0; pushdn( u );
if ( ql <= mid ) addeq( ret, query( u << 1, l, mid, ql, qr ) );
if ( mid < qr ) addeq( ret, query( u << 1 | 1, mid + 1, r, ql, qr ) );
return ret;
}
} sgt[4]; inline void solve( const int u, const int l, const int r ) {
/* bound check and divide down. */
auto& qry( qbuc[u] );
if ( l == r ) {
all[u] = mul( a[l], a[l] );
for ( const auto& x: qry ) addeq( ans[x.id], all[u] );
return ;
}
int mid = l + r >> 1;
solve( u << 1, l, mid ), solve( u << 1 | 1, mid + 1, r );
all[u] = add( all[u << 1], all[u << 1 | 1] ); /* initialize some information. */
static int x[MAXN + 5], y[MAXN + 5], xy[MAXN + 5]; // x->min, y->max.
x[mid] = y[mid] = a[mid];
per ( i, mid - 1, l ) {
x[i] = imin( a[i], x[i + 1] ), y[i] = imax( a[i], y[i + 1] );
}
x[mid + 1] = y[mid + 1] = a[mid + 1];
rep ( i, mid + 2, r ) {
x[i] = imin( a[i], x[i - 1] ), y[i] = imax( a[i], y[i - 1] );
}
rep ( i, l, r ) xy[i] = mul( x[i], y[i] );
#define R 1, 1, r - mid
sgt[0].build( R, NULL );
sgt[1].build( R, x + mid );
sgt[2].build( R, y + mid );
sgt[3].build( R, xy + mid ); /* finally begin to solve queries. */
std::sort( qry.begin(), qry.end() );
for ( int i = mid, j = int( qry.size() ) - 1,
px = mid + 1, py = mid + 1; i >= l; --i ) {
while ( px <= r && x[i] <= x[px] ) ++px;
while ( py <= r && y[i] >= y[py] ) ++py;
int pl = imin( px, py ), pr = imax( px, py );
if ( mid + 1 < pl ) sgt[0].modify( R, 1, pl - mid - 1, xy[i] );
if ( px < py ) sgt[1].modify( R, px - mid, py - mid - 1, y[i] );
if ( py < px ) sgt[2].modify( R, py - mid, px - mid - 1, x[i] );
if ( pr <= r ) sgt[3].modify( R, pr - mid, r - mid, 1 ); while ( ~j && qry[j].l == i ) {
int qr = qry[j].r - mid;
addeq( ans[qry[j].id], add(
add( sgt[0].query( R, 1, qr ), sgt[1].query( R, 1, qr ) ),
add( sgt[2].query( R, 1, qr ), sgt[3].query( R, 1, qr ) ) ) );
if ( i == l && qry[j].r == r ) addeq( ans[qry[j].id], all[u] );
--j;
}
} /* update all[u] with contribution in current section. */
addeq( all[u], add(
add( sgt[0].query( R, 1, r - mid ), sgt[1].query( R, 1, r - mid ) ),
add( sgt[2].query( R, 1, r - mid ), sgt[3].query( R, 1, r - mid ) ) ) );
#undef R
} int main() {
freopen( "sequence.in", "r", stdin );
freopen( "sequence.out", "w", stdout ); n = rint(), q = rint();
rep ( i, 1, n ) a[i] = rint();
rep ( i, 1, q ) {
int l = rint(), r = rint();
hang( 1, 1, n, l, r, i );
} solve( 1, 1, n );
rep ( i, 1, q ) wint( ans[i] ), putchar( '\n' );
return 0;
}

Solution -「多校联训」古老的序列问题的更多相关文章

  1. Solution -「多校联训」排水系统

    \(\mathcal{Description}\)   Link.   在 NOIP 2020 A 的基础上,每条边赋权值 \(a_i\),随机恰好一条边断掉,第 \(i\) 条段的概率正比于 \(a ...

  2. Solution -「多校联训」I Love Random

    \(\mathcal{Description}\)   给定排列 \(\{p_n\}\),可以在其上进行若干次操作,每次选取 \([l,r]\),把其中所有元素变为原区间最小值,求能够得到的所有不同序 ...

  3. Solution -「多校联训」签到题

    \(\mathcal{Description}\)   Link.   给定二分图 \(G=(X\cup Y,E)\),求对于边的一个染色 \(f:E\rightarrow\{1,2,\dots,c\ ...

  4. Solution -「多校联训」朝鲜时蔬

    \(\mathcal{Description}\)   Link.   破案了,朝鲜时蔬 = 超现实树!(指写得像那什么一样的题面.   对于整数集 \(X\),定义其 好子集 为满足 \(Y\sub ...

  5. Solution -「多校联训」消失的运算符

    \(\mathcal{Description}\)   Link.   给定长度为 \(n\) 的合法表达式序列 \(s\),其中数字仅有一位正数,运算符仅有 - 作为占位.求将其中恰好 \(k\) ...

  6. Solution -「多校联训」假人

    \(\mathcal{Description}\)   Link.   一种物品有 长度 和 权值 两种属性,现给定 \(n\) 组物品,第 \(i\) 组有 \(k_i\) 个,分别为 \((1,a ...

  7. Solution -「多校联训」Sample

    \(\mathcal{Description}\)   Link   (稍作简化:)对于变量 \(p_{1..n}\),满足 \(p_i\in[0,1],~\sum p_i=1\) 时,求 \(\ma ...

  8. Solution -「多校联训」光影交错

    \(\mathcal{Description}\)   Link.   一个游戏包含若干次卡牌抽取,每次以 \(p_l\) 的概率得到 \(+1\),\(p_d\) 的概率得到 \(-1\),否则得到 ...

  9. Solution -「多校联训」数学考试

    \(\mathcal{Description}\)   Link.   给定 \(n\) 个函数,第 \(i\) 个有 \(f_i(x)=a_ix^3+b_ix^2+cx_i+d~(x\in[l_i, ...

随机推荐

  1. 禁止yum update 自动更新系统内核

    使用yum update更新系统软件时,禁止升级内核,可以防止产生因不兼容导致的未知错误. 设置前请先备份原设置文件yum.conf cp /etc/yum.conf    /etc/yum.conf ...

  2. win10 防火墙配置 允许局域网其他设备访问本地工程

    1.进入防护墙并找到高级设置 2.选择属性 3.将入站连接设为允许,有三个别忘了,[域配置文件,专用配置文件,公用配置文件]

  3. 经典定长指令-修改EIP

    1.0x70~0x7F EIP无法像通用寄存器那样用mov来修改,只能通过类似于jz,JNB,JNE JBE,call等的跳转指令来进行修改 条件跳转,后跟一个字节立即数的偏移(有符号),共两个字节. ...

  4. 离线环境安装使用 Ansible

    之前写了一篇介绍 Ansible 的文章 ,今天回顾看来写的有些匆忙,一些具体的操作步骤都没有讲明白,不利于读者复现学习.最近又申请了一个几百台机器的环境,正好借此机会把如何在离线环境中使用 Ansi ...

  5. Redis内存分析工具之redis-rdb-tools的安装与使用

    操作系统:Centos7    1.redis-rdb-tools工具是用python语言编写的,所以首先需要安装python: 安装: (1)用 wget 下载 python 2.7 并解压( 如果 ...

  6. echart实现实时疫情图

    直接上代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </h ...

  7. 同步gitlab与github

    1.找到setting 2.找到左下方的developer setting 3.按标好的数字依次执行 4.填写note并勾选repo 5.在最左下方勾选 6.保存生成的新的token到其他地方,之后你 ...

  8. 微信小程序云开发框架

    概述 一直做后端服务器开发,最近看了一篇文章介绍小程序的云开发模式,觉得挺有意思,就尝试了一下,由本文做个记录. 因为不是专业的小程序开发人员,也没有做过网页开发,所以论述中出现错误难以避免,请多谅解 ...

  9. 【转载】ASP.NET 内联代码、内联表达式、数据绑定表达式使用方法罗列(形式就是常说的尖括号 百分号 等于号 井号)

    ASP.NET 内联代码.内联表达式.数据绑定表达式使用方法罗列(形式就是常说的尖括号 百分号 等于号 井号) 今天在做渭南电脑维修网的一个小功能时遇到了一些问题,因此特别列出,以备他日之用. 首先对 ...

  10. golang中通过bufio和os包读取终端中输入的一行带空格的数据

    1. 如果读取不带空格的数据可以使用fmt.Scan或fmt.Scanln读取一个或多个值,但是不能读取带空格的数据,可以使用bufio和os两个包结合 package main import ( & ...