• Solution -「多校联训」古老的序列问题


    (mathcal{Description})

      Link.

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

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

      (n,qle10^5)

    (mathcal{Solution})

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

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

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

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

      Ummm... 有 (mathcal O(nlog 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( '
    ' );
    	return 0;
    }
    
    
  • 相关阅读:
    [转]狼的故事8:生存就是坚持
    [转]狼的故事7:单枪匹马的代价
    如何在GridView的Footer内显示总计?
    javascript中如何正确将日期(Date)字符串转换为日期(Date)对象?
    无限级分类(非递归算法/存储过程版/GUID主键)完整数据库示例_(1)表结构
    [转]狼的故事12:王者的风范
    [转]狼的故事2:光线背后的嚎叫
    vs.net2008正式版发布并提供下载(英文版)
    [转]狼的故事11:以牙还牙
    [转]狼的故事3:百分之百的死亡
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15367018.html
Copyright © 2020-2023  润新知