[BZOJ3339]Rmq Problem 线段树应用

来源:互联网 发布:淘宝店铺装修设计方案 编辑:程序博客网 时间:2024/06/07 04:53

躺在前面

被大佬hhl(Monica)说me心里没B数了
哎╮(╯▽╰)╭,果然还是太弱了……

题面

题目传送门!嘟嘟嘟嘟嘟(读条ing)————>biu
这是一道权限题,把题面贴过来吧
这里写图片描述
这里写图片描述
这里写图片描述
Sample Input
7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7
Sample Output
3
0
3
2
4
这里写图片描述


题解

me突然觉得这个字体颜色真好玩hhhhh

题目要求的是求一些区间的mex值。
我们应该可以很快的求出以某一个点为L,任意R>=L的mex[L,R]值,这只需要O(n)的for一遍就可以实现。但是对于所有询问都这样处理明显比较暴力,于是考虑不同的区间mex值的关系。

对于任意一个区间[L,R],设L位置的数为x,假如我们已知这个区间的mex值,需要求出[L+1,R]这个区间的mex值。
设a[i]表示i位置的数,维护一个next数组表示,下一个在该位置的数字出现的位置,比如next[i]表示下一个a[i]出现的位置

如果next[x]在R的左边,那么[L+1,R]的mex与[L,R]的mex值是一样的。(这是显然的,因为[L,R]中出现过的数字集合和[L+1,R]的一样,mex当然一样)
如果next[x]在R的右边,那么[L+1,R]的mex=min(mex,a[L])(这也比较显然,[L+1,R]的集合中比[L,R]少了一个a[L])

又因为,左端点相同的时候,mex值单调递增。我们维护”以now为左端点,任意R>=now为右端点的mex值”。可以注意到每当L增加1,就会有一个区间的mex可能被修改,这一步我们用线段树实现。

然后就可以乱搞了,离线查询,按照L排序,每次都按照上述维护,查询即可。

代码
#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;int N , M , mex[200005] , nxt[200005] , a[200005] , head[200005] ;int ans[200005] , vis[200005] ;struct Query{    int L , R , id ;    bool operator < ( const Query &A ) const {        return L <  A.L ;    }}Q[200005] ;struct node{    int minn ;    node *ls , *rs ;    void pushdown(){        ls->minn = min( ls->minn , minn ) ;        rs->minn = min( rs->minn , minn ) ;    }}w[400005] , *tw = w , *root ;node *build( int lf , int rg ){    node *nd = ++tw ;    if( lf == rg ){        nd->minn = mex[lf] ;        return nd ;    }    int mid = ( lf + rg ) >> 1 ;    nd->ls = build( lf , mid ) ;    nd->rs = build( mid+1 , rg ) ;    nd->minn = 0x3f3f3f3f ;    return nd ;}void Modify( node *nd , int lf , int rg , int L , int R , int delta ){    if( L <= lf && rg <= R ){        nd->minn = min( nd->minn , delta ) ;        return ;    }    int mid = ( lf + rg ) >> 1 ;    nd->pushdown() ;    if( L <= mid ) Modify( nd->ls , lf  , mid , L , R , delta ) ;    if( R >  mid ) Modify( nd->rs , mid+1, rg , L , R , delta ) ;}int Query( node *nd , int lf , int rg , int pos ){    if( lf == rg ) return nd->minn ;    int mid = ( lf + rg ) >> 1 ;    nd->pushdown() ;    if( pos <= mid ) return Query( nd->ls , lf  , mid , pos ) ;    else             return Query( nd->rs , mid+1, rg , pos ) ;}void solve(){    for( register int i = 1 ; i <= M ; i ++ )        scanf( "%d%d" , &Q[i].L , &Q[i].R ) , Q[i].id = i ;    sort( Q + 1 , Q + M + 1 ) ;    for( register int i = 1 , now = 1 ; i <= M ; i ++ ){        int L = Q[i].L , R = Q[i].R , id = Q[i].id ;        while( now < L ){            Modify( root , 1 , N , now , nxt[now] ? nxt[now] - 1 : N , a[now] ) ;            now++ ;        }        ans[id] = Query( root , 1 , N , R ) ;    }    for( register int i = 1 ; i <= M ; i ++ )        printf( "%d\n" , ans[i] ) ;}int read_(){    int rt = 0;    char ch = getchar() ;    while( ch < '0' || ch > '9' ) ch = getchar() ;    while( ch >='0' && ch <='9' ) rt = (rt<<3) + (rt<<1) + ch - '0' , ch = getchar() ;    return rt;}int main(){    scanf( "%d%d" , &N , &M ) ;    for( register int i = 1 ; i <= N ; i ++ )        a[i] = read_() ;    for( register int i = 1 , now = 0 ; i <= N ; i ++ ){        vis[a[i]] = 1 ;        while( vis[now] ) ++now ;        mex[i] = now ;    }    for( register int i = N ; i >= 1 ; i -- ){        nxt[i] = head[a[i]] ;        head[a[i]] = i ;     }    root = build( 1 , N ) ;    solve() ;}
原创粉丝点击