CF817F MEX Queries

题意

维护一个\(01\)串,一开始全部都是\(0\)
\(3\)种操作
\(1.\)把一个区间都变为\(1\)
\(2.\)把一个区间都变为\(0\)
\(3.\)把一个区间的所有数字翻转过来
每次操作完成之后询问区间最小的\(0\)的位置
\(l,r<=10^{18}\)

Sol

直接上线段树,如果这个区间左边是满的就去右边,否则去左边
动态开点,加上\(lazy\)
但这样会爆空间

所以把区间离散化
注意要离散\(1\),\(l\),\(r\),\(l+1\),\(r+1\)
这些都可能会出现答案

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(4e5 + 5);

IL ll Input(){
    RG ll x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, len, opt[_];
ll ql[_], qr[_], o[_];
struct Segment{
    int sum, rev, tag;
} T[_ << 2];

IL void Adjust1(RG int x, RG int l, RG int r, RG int v){
    T[x].rev = 0, T[x].tag = v--;
    T[x].sum = v * (r - l + 1);
}

IL void Adjust2(RG int x, RG int l, RG int r){
    T[x].sum = r - l + 1 - T[x].sum;
    T[x].rev ^= 1;
}

IL void Pushdown(RG int x, RG int l, RG int r){
    RG int mid = (l + r) >> 1, ls = x << 1, rs = x << 1 | 1;
    if(T[x].tag){
        Adjust1(ls, l, mid, T[x].tag);
        Adjust1(rs, mid + 1, r, T[x].tag);
        T[x].tag = 0;
    }
    if(T[x].rev){
        Adjust2(ls, l, mid);
        Adjust2(rs, mid + 1, r);
        T[x].rev = 0;
    }
}

IL void Modify(RG int x, RG int l, RG int r, RG int L, RG int R, RG int v){
    if(L <= l && R >= r){
        Adjust1(x, l, r, v);
        return;
    }
    Pushdown(x, l, r);
    RG int mid = (l + r) >> 1;
    if(L <= mid) Modify(x << 1, l, mid, L, R, v);
    if(R > mid) Modify(x << 1 | 1, mid + 1, r, L, R, v);
    T[x].sum = T[x << 1].sum + T[x << 1 | 1].sum;
}

IL void Reverse(RG int x, RG int l, RG int r, RG int L, RG int R){
    if(L <= l && R >= r){
        Adjust2(x, l, r);
        return;
    }
    Pushdown(x, l, r);
    RG int mid = (l + r) >> 1;
    if(L <= mid) Reverse(x << 1, l, mid, L, R);
    if(R > mid) Reverse(x << 1 | 1, mid + 1, r, L, R);
    T[x].sum = T[x << 1].sum + T[x << 1 | 1].sum;
}

IL int Query(RG int x, RG int l, RG int r){
    if(l == r) return l;
    Pushdown(x, l, r);
    RG int mid = (l + r) >> 1, ans;
    if(T[x << 1].sum != mid - l + 1) ans = Query(x << 1, l, mid);
    else ans = Query(x << 1 | 1, mid + 1, r);
    T[x].sum = T[x << 1].sum + T[x << 1 | 1].sum;
    return ans;
}

int main(RG int argc, RG char *argv[]){
    n = Input(), o[++len] = 1;
    for(RG int i = 1; i <= n; ++i){
        opt[i] = Input(), ql[i] = Input(), qr[i] = Input();
        o[++len] = ql[i], o[++len] = qr[i];
        o[++len] = ql[i] + 1, o[++len] = qr[i] + 1;
    }
    sort(o + 1, o + len + 1), len = unique(o + 1, o + len + 1) - o - 1;
    for(RG int i = 1; i <= n; ++i){
        ql[i] = lower_bound(o + 1, o + len + 1, ql[i]) - o;
        qr[i] = lower_bound(o + 1, o + len + 1, qr[i]) - o;
        if(opt[i] == 1) Modify(1, 1, len, ql[i], qr[i], 2);
        else if(opt[i] == 2) Modify(1, 1, len, ql[i], qr[i], 1);
        else Reverse(1, 1, len, ql[i], qr[i]);
        printf("%lld\n", o[Query(1, 1, len)]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cjoieryl/p/8619821.html

时间: 2024-09-29 12:02:49

CF817F MEX Queries的相关文章

CF817F MEX Queries(线段树上二分)

题意 维护一个01串,一开始全部都是0 3种操作 1.把一个区间都变为1 2.把一个区间都变为0 3.把一个区间的所有数字翻转过来 每次操作完成之后询问区间最小的0的位置 l,r<=10^18 题解 区间操作想到线段树,离散化不用说,l,r太大了. 1,2,3操作非常好维护. 然后在查询中二分查询就好了. 一开始看别的博客(对,我看题解了,太菜)说要加1节点和r+1节点不知道为什么. 因为我的查询想的是,查询前面全都是1的区间的长度.后来发现做不了.就乖乖照题解做了. 1 #include<i

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

Codeforces 817F - MEX Queries

817F - MEX Queries 思路: 离线+离散化+线段树 代码: #include<bits/stdc++.h> using namespace std; #define LL long long #define pb push_back #define ls rt<<1,l,m #define rs rt<<1|1,m+1,r const int N=1e5+5; int t[N],tree[N*16],lazy[N*16]; LL l[N],r[N]; v

Educational Codeforces Round 23 A-F 补题

A Treasure Hunt 注意负数和0的特殊处理.. 水题.. 然而又被Hack了 吗的智障 #include<bits/stdc++.h> using namespace std; int main() { int sa,sb,da,db,x,y; scanf("%d%d%d%d%d%d",&sa,&sb,&da,&db,&x,&y); sa=da-sa;sb=db-sb; if(sa<0)sa*=-1; if(

线段树离散化

主要思路是在离散化前把右端点++, 离散化后右端点-1. 1. CF 610D Vika and Segments 大意: 给定$n$条与坐标轴平行的线段, 求一共占了多少点 #include <iostream> #include <algorithm> #include <cstdio> #include <math.h> #include <set> #include <map> #include <queue> #

BZOJ 3585 mex 莫队算法+分块

题目大意:给定一个长度为n的数组,m次询问某个区间内的mex值 怒写莫队233 将权值分成√n块,记录每个权值的出现次数以及每块内有多少权值出现过 修改O(1)即可完成 查询时首先扫一遍找到第一个块内有没有覆盖的点的块 然后在块内暴力查找 时间复杂度O(√n) 套个莫队 总时间复杂度O(m√n) #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include

HDU4027 Can you answer these queries 线段树区间求和+剪枝

给了你n,然后n个数字在一个数组中,接下来m个询问,每个询问三个数字 t,x,y,若t==0,那么修改区间[x,y]的每一个值,变为原来每个位置上的数 开根号取整,若t==1,那么对区间[x,y]求和 由于n,m,很大,所以树状数组铁定超时,若直接用线段树来做区间修改,那么也是超时,这类题目没别的方法了,静心剪枝,发现题目给的数据范围为2^63,有没有发现,2^63开根号 绝对不需要开10次,就能到1,到1以后就不需要再开了,意思就是若有某个区间[x,y]每一个点的值都为1时,这一段区间事实上是

[BZOJ3585][BZOJ3339]mex

试题描述 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 输入 第一行n,m.第二行为n个数.从第三行开始,每行一个询问l,r. 输出 一行一个数,表示每个询问的答案. 输入示例 5 5 2 1 0 2 1 3 3 2 3 2 4 1 2 3 5 输出示例 1 2 3 0 3 数据规模及约定 对于100%的数据:1<=n,m<=2000000<=ai<=1091<=l<=r<=n 题解 首先离线,将询问按右端

[CodeChef - GERALD07 ] Chef and Graph Queries

Read problems statements in Mandarin Chineseand Russian. Problem Statement Chef has a undirected graph G. This graph consists of N vertices and M edges. Each vertex of the graph has an unique index from 1 to N, also each edge of the graph has an uniq