【CodeForces817F】MEX Queries

题目链接

MEX Queries

题目描述

You are given a set of integer numbers, initially it is empty. You should perform \(n\) queries.

There are three different types of queries:

  • \(1\ l\ r\) — Add all missing numbers from the interval \([l, r]\)
  • \(2\ l\ r\) — Remove all present numbers from the interval \([l, r]\)
  • \(3\ l\ r\) — Invert the interval \([l, r]\) — add all missing and remove all present numbers from the interval \([l, r]\)
    After each query you should output MEX of the set — the smallest positive (\(MEX  \ge 1\)) integer number which is not presented in the set.

输入格式

The first line contains one integer number \(n\) (\(1 \le n \le 10^5\)).

Next \(n\) lines contain three integer numbers \(t, l, r\) (\(1 \le t \le 3, 1 \le l \le r \le 10^{18}\)) — type of the query, left and right bounds.

输出格式

Print \(MEX\) of the set after each query.

样例输入1

3
1 3 4
3 1 6
2 1 3

样例输出1

1
3
1

样例输入2

4
1 1 3
3 5 6
2 4 4
3 1 6

样例输出2

4
4
4
1

题解

题意:维护一个集合,有三种操作,第一种操作将区间\([l,r]\)内所有元素加入集合中;第二种操作将区间\([l,r]\)内所有在集合内的元素从集合中删除;第三种操作将区间\([l,r]\)中所有在集合内的元素删除,不在集合内的元素加入集合。
要求每次操作后输出最小的没有在集合内的元素。
很明显是一道线段树水题,每次区间修改加上懒标记就好了。
但是我们发现这里区间的范围在\(1e18\)内,所幸修改操作数在\(1e5\)内,所以我们可以离散化一下。
因为如果直接离散化\(l,r\)的话边界情况会比较难处理,每次操作要离散3个点,所以我这里是离散化\(l,r+1\),把区间离散化而不是把点离散化。
我们用\(i\)表示元素\(i\)和元素\(i-1\)的交界,那么我们要修改\([l,r]\)的时候就要离散化\(l\)\(l-1\)的交界和\(r\)\(r+1\)的交界,也就是\(l,r+1\)两个点。
上代码:

#include<bits/stdc++.h>
using namespace std;
int n;
struct aa{
    int t;
    long long l,r;
}a[500009];
int lt=1;
struct cc{
    long long s;
    int from;
    bool k;
}to[500009];
struct bb{
    int x;
    int ld;
}p[4000009];
bool cmp(cc x,cc y){return x.s<y.s;}
void dn(int u,int l,int r){
    if(p[u].ld&(1<<2)){
        p[u*2].ld=p[u*2+1].ld=(1<<2);
        p[u].x=r-l;
    }
    if(p[u].ld&(1<<1)){
        p[u*2].ld=p[u*2+1].ld=(1<<1);
        p[u].x=0;
    }
    if(p[u].ld&1){
        p[u].x=r-l-p[u].x;
        if(p[u*2].ld&(1<<2)) p[u*2].ld=(1<<1);
        else if(p[u*2].ld&(1<<1)) p[u*2].ld=(1<<2);
        else p[u*2].ld^=1;
        if(p[u*2+1].ld&(1<<2)) p[u*2+1].ld=(1<<1);
        else if(p[u*2+1].ld&(1<<1)) p[u*2+1].ld=(1<<2);
        else p[u*2+1].ld^=1;
    }
    p[u].ld=0;
}
void dfs(int u,int l,int r,int x){
    dn(u,l,r);
    if(r<=a[x].l || l>=a[x].r) return;
    if(l>=a[x].l && r<=a[x].r){
        p[u].ld=(1<<(3-a[x].t));
        dn(u,l,r);
        if(r==l+1) return;
        dn(u*2,l,(l+r)/2);
        dn(u*2+1,(l+r)/2,r);
        p[u].x=p[u*2].x+p[u*2+1].x;
        return;
    }
    if(r==l+1) return;
    dfs(u*2,l,(l+r)/2,x);
    dfs(u*2+1,(l+r)/2,r,x);
    p[u].x=p[u*2].x+p[u*2+1].x;
}
void fd(int u,int l,int r){
    dn(u,l,r);
    if(p[u].x==0){
        printf("%lld\n",to[l].s);
        return;
    }
    else if(p[u].x==r-l){
        printf("%lld\n",to[r].s);
        return;
    }else{
        dn(u*2,l,(l+r)/2);
        if(p[u*2].x==(l+r)/2-l) fd(u*2+1,(l+r)/2,r);
        else fd(u*2,l,(l+r)/2);
    }
}
int main(){
    scanf("%d",&n);
    for(int j=1;j<=n;j++){
        scanf("%d%lld%lld",&a[j].t,&a[j].l,&a[j].r);
        a[j].r++;
        to[j*2-1].s=a[j].l;
        to[j*2-1].from=j;
        to[j*2].s=a[j].r;
        to[j*2].from=j;
        to[j*2].k=1;
    }
    to[n*2+1].s=1;
    sort(to+1,to+n*2+2,cmp);
    if(to[1].k) a[to[1].from].r=1;
    else a[to[1].from].l=1;
    for(int j=2;j<=n*2+1;j++){
        if(to[j].s!=to[lt].s) to[++lt]=to[j];
        if(to[j].k) a[to[j].from].r=lt;
        else a[to[j].from].l=lt;
    }
    for(int j=1;j<=n;j++){
        dfs(1,1,lt,j);
        fd(1,1,lt);
    }
    return 0;
}
posted @ 2020-08-11 19:03  oblivionl  阅读(166)  评论(0编辑  收藏  举报