[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() ;}
- [BZOJ3339]Rmq Problem 线段树应用
- BZOJ3339: Rmq Problem 线段树
- 【BZOJ3339】Rmq Problem【离线】【线段树】【mex】
- [BZOJ3339]Rmq Problem(离线+线段树)
- bzoj3339 Rmq Problem(离线+线段树)
- 【bzoj3339】Rmq Problem
- 【BZOJ3339】Rmq Problem
- bzoj3339 Rmq Problem
- 【bzoj3339】Rmq Problem
- bzoj3339: Rmq Problem
- [BZOJ3339] Rmq Problem&&[BZOJ3585] mex
- bzoj3339(线段树)
- [bzoj3339]mex(线段树)
- bzoj 3339: Rmq Problem(线段树)
- bzoj 3339 Rmq problem 离线+线段树
- hdu-5443-The Water Problem -裸的RMQ线段树
- BZOJ 3339 Rmq Problem【离线,值域线段树
- BZOJ 3339: Rmq Problem 穿了棉袄的线段树
- x264和ac编译
- HNU OJ题库 1003D相邻数对问题
- BZOJ 2957: 楼房重建 [分块][线段树]
- 第4周项目5(1)猴子选大王
- HD-1213-How Many Tables(并查集)
- [BZOJ3339]Rmq Problem 线段树应用
- 动态规划算法之:最长公共子序列 & 最长公共子串(LCS)
- RMQ算法小结(st实现)
- 8、C#里面的异常处理
- poj1556 The Doors(建图spfa+判断线段交)
- Javaweb学习总结-(六)
- 欢迎使用CSDN-markdown编辑器
- bzoj 1014 [JSOI2008]火星人prefix 哈希+splay
- No Target Architecture