1. 程式人生 > 實用技巧 >【CodeForces817F】MEX Queries

【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\),把區間離散化而不是把點離散化。
上程式碼:

#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;
}