zoukankan      html  css  js  c++  java
  • RMQ / mex

    题意

    给出一个长为(n)的序列,有(m)个询问,每次询问([l,r])区间内第一个没出现过的最小自然数(即求这个区间的(mex)


    解法

    ( t {CCPC})网络同步赛的第二题( t{array})很像

    同样也是对权值建树,每个权值保存一个位置

    但不同的是那一道题保证了它是一个排列,也就是([1,n])每个数最多出现一次且一定会出现一次

    而这道题并没有保证这是一个排列

    所以我们考虑使用主席树,对每个前缀区间建树

    而此时每个位置上保存的是该数最后一次出现的位置

    这样的好处是显而易见的,如果对于([1,R])这个前缀,我们找到的一个数最后一次出现的位置如果在([L,R])之间,那么它一定不合法

    我们保存父子关系中位置的最小值

    每次对于([L,R])这个区间,我们在第(R)颗线段树上查询

    如果左子树的权值小于(L),说明左子树中一定有合法的答案,右子树同理

    还有一个需要注意的:

    因为每次查询的答案不会超过(n),所以我们可以不用离散化,对于大于(n)的数据不插入即可

    为了方便处理,把所有数都加上了(1)避免权值为(0)的情况,查询时再减回来

    可以对比一下这一题与( t{array})

    为什么这一题中的线段树要取(min),而那一颗中要取(max)

    因为在那一题中,合法的位置是在大的一端,而这一题不同


    代码

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    void fast_IO();
    
    const int N = 2e5 + 10;
    
    int n, m;
    int rt[N];
    
    struct CTree {
    	
    	int sz;
    	int ls[N * 20], rs[N * 20], val[N * 20];
    	
    	void clear() { sz = 0; }
    	
    	int newnode() {
    		++sz;
    		ls[sz] = rs[sz] = val[sz] = 0;
    		return sz;	
    	}
    	
    	void mkchain(int &x, int y, int l, int r, int k, int v) {
    		x = newnode();
    		ls[x] = ls[y], rs[x] = rs[y];
    		if (l == r)	return val[x] = v, void();
    		int mid = l + r >> 1;
    		if (k <= mid)
    			mkchain(ls[x], ls[y], l, mid, k, v);
    		else
    			mkchain(rs[x], rs[y], mid + 1, r, k, v);
    		val[x] = min(val[ls[x]], val[rs[x]]);
    	}
    	
    	int query(int x, int l, int r, int k) {
    		if (l == r)	return l - 1;
    		int mid = l + r >> 1;
    		if (val[ls[x]] < k)
    			return query(ls[x], l, mid, k);
    		else 
    			return query(rs[x], mid + 1, r, k);
    	}
    	
    } tr;
    
    int main() {
    	
    	fast_IO();
    	tr.clear();
    	
    	cin >> n >> m;
    	
    	int x, y;
    	for (int i = 1; i <= n; ++i) {
    		cin >> x;
    		tr.mkchain(rt[i], rt[i - 1], 1, n + 1, x + 1, i);	
    	}
    	
    	for (int i = 1; i <= m; ++i) {
    		cin >> x >> y;
    		cout << tr.query(rt[y], 1, n + 1, x) << endl;	
    	}
    	
    	return 0;
    }
    
    void fast_IO() {
    	ios :: sync_with_stdio(false);
    	cin.tie(NULL), cout.tie(NULL);	
    }
    
  • 相关阅读:
    使用vue-cli创建项目(包含npm和cnpm的安装nodejs的安装)
    关于时区、时间戳引起的bug理解
    设置java、maven环境变量(怕麻烦以后直接来这里复制)
    回去看
    dockerfile各种命令解析
    Python+Appium环境搭建
    Python Selenium unittest+HTMLTestRunner实现 自动化测试及发送测试报告邮件
    Python Selenium 文件下载
    Python Selenium 文件上传之Autoit
    Python Selenium 文件上传之SendKeys
  • 原文地址:https://www.cnblogs.com/VeniVidiVici/p/11459928.html
Copyright © 2011-2022 走看看