GYM105698G-Get Mex Range Add Linear

GYM105698G-Get Mex Range Add Linear

题目大意

\(n\) 个集合,初始每个集合中,只含有元素 \(0\) 。接下来有 \(q\) 次查询

  1. \(l \space r\), 向 $l $ 到$ r$ 中每一个集合中添加元素 \(l-i+1\)
  2. \(x\) 输出第 \(x\) 个集合的 \(mex\)

\(Hint\)

如果第 \(i\) 个集合中有数字 \(x\) 那么 \(i-x+1\) 一定作为一个左端点,且右端点大于等于 \(i\)

题解

作为一个左端点,我们可以记录其右端点的最大值,在极值线段树上维护。

对于第 \(i\) 个集合的查询。我们只需要找到左边第一个值小于其的位置即可。我们可以在线段树上二分区间最小值维护。

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define umap unordered_map
#define endl '\n'
using namespace std;
using i128 = __int128;
const int mod =1e9+7;
template <typename T>void read(T&x){
    x=0;int f = 1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
    x*=f;
}
template <typename T>void print(T x) {
     if (x < 0) { putchar('-'); x = -x; }
     if (x > 9) print(x / 10);
     putchar(x % 10 + '0');
}
#define int long long
class SegmentTree {
private:
    int n;
    vector<int> arr;       
    vector<int> tree_max;   
    vector<int> tree_min;   
    vector<int> lazy;       
    
    void build(int node, int start, int end) {
        if (start == end) {
            tree_max[node] = arr[start];
            tree_min[node] = arr[start];
        } else {
            int mid = start + end >> 1;
            int left_node = node << 1;
            int right_node = node << 1 | 1;
            build(left_node, start, mid);
            build(right_node, mid + 1, end);
            tree_max[node] = max(tree_max[left_node], tree_max[right_node]);
            tree_min[node] = min(tree_min[left_node], tree_min[right_node]);
        }
    }
    
    void pushDown(int node) {
        if (lazy[node] != 0) {
            tree_max[node << 1] += lazy[node];
            tree_max[node << 1 | 1] += lazy[node];
            tree_min[node << 1] += lazy[node];
            tree_min[node << 1 | 1] += lazy[node];
            lazy[node << 1] += lazy[node];
            lazy[node << 1 | 1] += lazy[node];
            lazy[node] = 0;
        }
    }
    
    void updateRange(int node, int start, int end, int l, int r, int val) {
        if (l <= start && end <= r) {
            tree_max[node] += val;
            tree_min[node] += val;
            lazy[node] += val;
            return;
        }
        
        pushDown(node);
        int mid = start + end >> 1;
        int left_node = node << 1;
        int right_node = node << 1 | 1;
        
        if (l <= mid) {
            updateRange(left_node, start, mid, l, r, val);
        }
        if (r > mid) {
            updateRange(right_node, mid + 1, end, l, r, val);
        }
        
        tree_max[node] = max(tree_max[left_node], tree_max[right_node]);
        tree_min[node] = min(tree_min[left_node], tree_min[right_node]);
    }
    
    int queryMax(int node, int start, int end, int l, int r) {
        if (l <= start && end <= r) {
            return tree_max[node];
        }
        
        pushDown(node);
        int mid = start + end >> 1;
        int left_node = node << 1;
        int right_node = node << 1 | 1;
        
        int left_max = INT_MIN;
        int right_max = INT_MIN;
        
        if (l <= mid) {
            left_max = queryMax(left_node, start, mid, l, r);
        }
        if (r > mid) {
            right_max = queryMax(right_node, mid + 1, end, l, r);
        }
        
        return max(left_max, right_max);
    }
    
    int queryMin(int node, int start, int end, int l, int r) {
        if (l <= start && end <= r) {
            return tree_min[node];
        }
        
        pushDown(node);
        int mid = start + end >> 1;
        int left_node = node << 1;
        int right_node = node << 1 | 1;
        
        int left_min = INT_MAX;
        int right_min = INT_MAX;
        
        if (l <= mid) {
            left_min = queryMin(left_node, start, mid, l, r);
        }
        if (r > mid) {
            right_min = queryMin(right_node, mid + 1, end, l, r);
        }
        
        return min(left_min, right_min);
    }

public:
    SegmentTree(const vector<int>& nums) {
        n = nums.size() - 1;  
        arr = nums;  
        tree_max.resize((n + 5) << 2, INT_MIN);
        tree_min.resize((n + 5) << 2, INT_MAX);
        lazy.resize((n + 5) << 2, 0);
        build(1, 1, n);
    }
    
    SegmentTree(int size) {
        n = size;
        arr.resize(n + 1, 0);  
        tree_max.resize((n + 5) << 2, INT_MIN);
        tree_min.resize((n + 5) << 2, INT_MAX);
        lazy.resize((n + 5) << 2, 0);
        build(1, 1, n);
    }
    
    SegmentTree(int size, int init_val) {
        n = size;
        arr.resize(n + 1, init_val);  
        tree_max.resize((n + 5) << 2, INT_MIN);
        tree_min.resize((n + 5) << 2, INT_MAX);
        lazy.resize((n + 5) << 2, 0);
        build(1, 1, n);
    }
    
    void update(int l, int r, int val) {
        updateRange(1, 1, n, l, r, val);
    }
    
    void update(int index, int val) {
        updateRange(1, 1, n, index, index, val);
    }
    
    void set(int index, int val) {
        int old_val = query(index); 
        int diff = val - old_val;    
        update(index, diff);         
    }
    
    int queryMax(int l, int r) {
        return queryMax(1, 1, n, l, r);
    }
    
    int queryMin(int l, int r) {
        return queryMin(1, 1, n, l, r);
    }
    
    int query(int index) {
        return queryMax(1, 1, n, index, index);  
    }
    
};
const int N=500005;
const int M=2000005;
inline void solve()
{
	int n,q;
	cin>>n>>q;
	SegmentTree maxn(n+1);
	while(q--)
	{
		int id;
		cin>>id;
		if(id==1)
		{
			int l,r;
			cin>>l>>r;
			maxn.set(l,max(maxn.query(l),r));
		}
		else
		{
			
			int x;
			cin>>x;
			auto check=[&](int v)
			{
				return maxn.queryMin(v,x)<x;
			};
			int l=0,r=x;
			while(l<r)
			{
				int mid=l+r+1>>1;
				if(check(mid))
				{
					l=mid;
				}
				else
				{
					r=mid-1;
				}
			}
			cout<<x-l+1<<endl;
			cout<<endl;
		}
	}
}

signed main()
{
	ios;
	int T=1;
//	cin>>T;
	for(;T--;) solve();
	return 0;
}

posted @ 2025-11-19 16:15  NDAKJin  阅读(0)  评论(0)    收藏  举报