BZOJ 3339: Rmq Problem 穿了棉袄的线段树

来源:互联网 发布:什么叫做网络 编辑:程序博客网 时间:2024/04/25 13:28

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 1332 Solved: 709

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

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

HINT

这里写图片描述

Source

By Xhr


题解:

这道题的线段树显然不是裸的


我们就是求一个区间mex嘛,于是我们可以把所有询问离线一下,按照左端点排序,然后每次维护的是对于这个左端点的一直到n的线段树,每个点都表示这个点到当前的这个左端点的mex值,计算方法其实很简单,我们记录一个nxt数组,nxt数组表示和这个点的值相同的值的下一个位置,如果这个值为0的话就赋为n+1,现在如果我们要从l转移到l+1,那么我们就看这个l,如果这个点可以影响到后面的话,也就是说,如果比后面的某个点的mex值小的话,那么删除了之后,显然这个点的mex值就应该变成l的值,因为l的值被删了,而mex表示的是第一个没有出现的值如果本来后面的就小的话就不影响,所以我们就可以讨论一下大小关系,然后取min值,我是抄的黄学长的代码,感觉线段树写的好不清真啊,主要是因为头有点昏,所以直接敲了一遍a了,希望复习吧

第一遍可以O(n)求mex,因为我们发现最开始从1到x的mex值都是递增的,因此可以利用这个递增性,O(n)地去求最开始的mex值,nxt值也可以O(n)求,只需要倒着for就可以了,真的是好巧妙啊,这题总之处处都很巧妙,很有意思


#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int INF = 0x7fffffff;int n,m,k=0;const int MAXN = 200005;int a[MAXN],sg[MAXN],ans[MAXN],nxt[MAXN],last[MAXN];struct Tree{ int mex; } tree[ MAXN * 4 ];bool mark[200001];struct Q{ int l, r, id; } q[200005];bool cmp(Q a,Q b) { return a.l < b.l; }void pushdown( int l, int r, int rt ) {    if( l == r ) return;    tree[ rt << 1 ].mex = min( tree[rt].mex, tree[ rt << 1 ].mex );    tree[ rt << 1 | 1 ].mex = min( tree[rt].mex, tree[ rt << 1 | 1 ].mex );}int query( int R, int l, int r, int rt ) {    if( tree[rt].mex != INF ) pushdown( l, r, rt );    if( l == r ) return tree[rt].mex;    int mid = ( l + r ) >> 1;    if( R <= mid ) return query( R, l, mid, rt << 1 );    else           return query( R, mid + 1, r, rt << 1 | 1 );}void modify( int L, int R, int val, int l, int r, int rt ) {    if( tree[rt].mex != INF ) pushdown( l, r, rt );    if( L == l && R == r ) { tree[rt].mex = min( tree[rt].mex, val ); return ; }    int mid = ( l + r ) >> 1;    if( R <= mid )     modify( L, R, val, l, mid, rt << 1 );    else if( L > mid ) modify( L, R, val, mid + 1, r, rt << 1 | 1 );    else { modify( L, mid, val, l, mid, rt << 1 ); modify( mid + 1, R, val, mid + 1, r, rt << 1 | 1 ); }}void build( int l, int r, int rt ) {    tree[rt].mex = INF;    if( l == r ) { tree[rt].mex = sg[l]; return; }    int mid = ( l + r ) >> 1;    build( l, mid, rt << 1 );    build( mid + 1, r, rt << 1 | 1 );}int main( ) {    scanf( "%d%d", &n, &m );    for( register int i = 1; i <= n; i++ ) scanf( "%d", &a[i] );    for( register int i = 1; i <= n; i++ ) {        mark[a[i]] = 1;        if( a[i] == k ) while( mark[k] ) k++;        sg[i] = k;     }    build( 1, n, 1 );    for( register int i = n; i > 0; i-- ) nxt[i] = last[a[i]], last[a[i]] = i;    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, cmp );    int now = 1;    for( register int i = 1; i <= m; i++ ) {        while( now < q[i].l ) {            if( !nxt[now] ) nxt[now] = n + 1;            modify( now, nxt[now] - 1, a[now], 1, n, 1 );            now++;        }        ans[q[i].id] = query( q[i].r, 1, n, 1 );    }    for( register int i = 1; i <= m; i++ ) printf( "%d\n", ans[i] );    return 0;}

这里写图片描述