• [HNOI2016]序列


    题目

      点这里看题目。

    分析

      考虑将所有子序列画成(n imes n)的表的形式,表中的元素((x,y))就表示子序列(a[x:y])的最小值。((x>y)((x,y)=0)
      那么,对于一个元素(a_i),记它左边第一个小于它的位置为(lef(i)),右边第一个小于等于它的位置为(rig(i))。那么,在表格中,从((lef(i)+1,i))((i,rig(i)-1))的这些序列的最小值,都会是(a_i)。因此,一个元素就相当于在这个表格上面进行了一次矩形覆盖。
      再考虑查询,对于查询((l,r)),它查询的实际就是表格上((l,l))((r,r))的元素和。考虑到(forall 1le i< l, lle jle r, (j,i)=0),因此,询问实际上等价于((l,1))((r,r))的元素和。
      接下来就是一个离线的扫描线问题了。将矩形覆盖分为两类,一类是已经被扫描线扫过了,一类是正在被扫描。对于第一类,我们可以用一个线段树(T_1)维护它的贡献(因为扫过了之后它的贡献就不会改变了);对于第二类,我们做一个差分,将它已经固定了的贡献((lef-1)*a)加入到(T_1)中,再用另一个线段树(T_2)维护当前扫描线上的情况。查询的时候,我们就可以将(T_2)的贡献乘上扫描线的位置,再与(T_1)的贡献相加,这样第二类矩形的贡献就可以算出来了。
      时间是(O(nlog_2n))

    代码

    #include <cstdio>
    #include <vector>
    #include <cstring>
    using namespace std;
    
    typedef long long LL;
    
    const int MAXN = 1e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
    	if( 9 < x ){ write( x / 10 ); }
    	putchar( x % 10 + '0' );
    }
    
    struct SegmentTree
    {
    	LL s[MAXN << 2], tag[MAXN << 2];
    	
    	SegmentTree() { memset( s, 0, sizeof s ), memset( tag, 0, sizeof tag ); }
    	
    	void upt( const int x ) { s[x] = s[x << 1] + s[x << 1 | 1]; }
    	void add( const int x, const LL v, const int l, const int r ) { s[x] += ( r - l + 1 ) * v, tag[x] += v; }
    	
    	void normalize( const int x, const int l, const int r )
    	{
    		if( ! tag[x] ) return ;
    		int mid = l + r >> 1;
    		add( x << 1, tag[x], l, mid ), add( x << 1 | 1, tag[x], mid + 1, r );
    		tag[x] = 0;
    	}
    	
    	void update( const int u, const int l, const int r, const int segL, const int segR, const LL val )
    	{
    		if( segL <= l && r <= segR ) { add( u, val, l, r ); return ; }
    		int mid = l + r >> 1; normalize( u, l, r );
    		if( segL <= mid ) update( u << 1, l, mid, segL, segR, val );
    		if( segR > mid ) update( u << 1 | 1, mid + 1, r, segL, segR, val );
    		upt( u );
    	}
    
    	LL query( const int u, const int l, const int r, const int segL, const int segR )
    	{
    		if( segL <= l && r <= segR ) return s[u];
    		LL ret = 0; int mid = l + r >> 1; normalize( u, l, r );
    		if( segL <= mid ) ret += query( u << 1, l, mid, segL, segR );
    		if( mid < segR ) ret += query( u << 1 | 1, mid + 1, r, segL, segR );
    		return ret;
    	}
    }T1, T2;
    
    vector<int> add[MAXN], sub[MAXN], q[MAXN];
    
    LL ans[MAXN], qL[MAXN], qR[MAXN];
    int a[MAXN], lef[MAXN], rig[MAXN], stk[MAXN];
    int N, Q, top;
    
    signed main()
    {
    	read( N ), read( Q );
    	for( int i = 1 ; i <= N ; i ++ ) read( a[i] );
    	for( int i = 1 ; i <= N ; i ++ )
    	{
    		while( top && a[stk[top]] >= a[i] ) rig[stk[top --]] = i;
    		stk[++ top] = i;
    	}
    	while( top ) rig[stk[top --]] = N + 1;
    	for( int i = N ; i ; i -- )
    	{
    		while( top && a[stk[top]] > a[i] ) lef[stk[top --]] = i;
    		stk[++ top] = i;
    	}
    	while( top ) lef[stk[top --]] = 0;
    	for( int i = 1 ; i <= N ; i ++ ) add[i].push_back( i ), sub[rig[i]].push_back( i );
    	for( int i = 1 ; i <= Q ; i ++ ) 
    	{
    		read( qL[i] ), read( qR[i] );
    		q[qR[i]].push_back( i );
    	}
    	int id;
    	for( int i = 1 ; i <= N ; i ++ )
    	{
    		for( int j = 0 ; j < add[i].size() ; j ++ )
    		{
    			id = add[i][j];
    			T1.update( 1, 1, N, lef[id] + 1, id, 1ll * ( i - 1 ) * a[id] );
    			T2.update( 1, 1, N, lef[id] + 1, id, a[id] );
    		}
    		for( int j = 0 ; j < sub[i].size() ; j ++ )
    		{
    			id = sub[i][j];
    			T1.update( 1, 1, N, lef[id] + 1, id, -1ll * ( i - 1 ) * a[id] );
    			T2.update( 1, 1, N, lef[id] + 1, id, - a[id] );
    		}
    		for( int j = 0 ; j < q[i].size() ; j ++ )
    		{
    			id = q[i][j];
    			ans[id] = 1ll * i * T2.query( 1, 1, N, qL[id], qR[id] ) - T1.query( 1, 1, N, qL[id], qR[id] );
    		}
    	}
    	for( int i = 1 ; i <= Q ; i ++ ) write( ans[i] ), putchar( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    win server 2012 服务器不能ping通
    Linux系统的文件目录结构
    怎样理解和识别 Linux 中的文件类型
    Linux(Centos 7)下安装Git并配置连接GitHub
    centos 7 下升级自带 sqlite3
    Pycharm项目上传到Github
    计算机存储单位:bit, Byte, KB, MB, GB, TB, PB, EB, ZB, BB
    ubuntu 删除命令
    influxDB 各个历史版本号,时间截止2020年9月27日
    使用Github做一个完全免费的个人网站
  • 原文地址:https://www.cnblogs.com/crashed/p/13024565.html
Copyright © 2020-2023  润新知