F. MEX Queries

F. MEX Queries

分析

不得不说,题目不算难。但是非常考验选手的基础。我会把我出的问题放出到最后,给大家一些错误提示。

我们使用动态开点维护权值线段树。

我们先来看四个操作。

1.把 [l,r] 中在集合中没有出现过的数添加到集合中。

直接区间覆盖,将区间[l,r]区间覆盖为1。加一个懒标记cov1

2.把 [l,r] 中在集合中出现过的数删除。

直接区间覆盖,将区间[l,r]区间覆盖0。加一个懒标记cov0

3.把 [l,r] 中在集合中没有出现过的数添加到集合中,并且将出现过的数删除。

直接区间取反。加一个懒标记tag

4.询问集合中最小的没有出现过的正整数

我们添加两个标记,all0all1,来统计区间是否全部都为01

我们关于树中结点的设计方面就是

struct Node
{
    bool tag,all1,all0,cov0,cov1;
}tr[N*200];
int ls[N*200],rs[N*200];

然后就是常规的pushdownpushup什么的了。这点不说了。

一些细节

我直接给大家展示我结构体的一步步变化。

除了最后答案中可以乘200,下面列举的其他的都不可以乘200,但不乘又会RE,我会一步步讲变化

struct Node
{
    int l,r;
    bool tag,all1,all0;
    int cov;
}tr[N*200];

最开始是这样写的,我用一个cov表示覆盖的是0还是1。不出所料的不行。

我就说省一下空间。

改成了这样。

struct Node
{
    int l,r;
    bool tag,all1,all0,cov1,cov0;
}tr[N*200];

不出所料还是寄了,这个原因是因为结构体有对齐操作。

也就是说我以为我的bool值只占了一个bit,其实占了好多个。

因此就把int类型的l,r直接提出来了。

struct Node
{
    bool tag,all1,all0,cov0,cov1;
}tr[N*200];
int ls[N*200],rs[N*200];

就过啦。

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
const ll inf = 2e18;

struct Node
{
    bool tag,all1,all0,cov0,cov1;
}tr[N*200];
int ls[N*200],rs[N*200];
int n,idx,root,m;

int init(int u)
{
    ls[u] = rs[u] = 0;
    tr[u].tag = tr[u].all1 = tr[u].cov0 = tr[u].cov1 = 0;
    tr[u].all0 = 1;
    return u;
}

void pushup(int u)
{
    tr[u].all1 = tr[ls[u]].all1 & tr[rs[u]].all1;
    tr[u].all0 = tr[ls[u]].all0 & tr[rs[u]].all0;
}

void changecov(Node &u,int k,ll l,ll r)
{
    u.tag = 0;
    if(k) u.cov1 = 1,u.cov0 = 0;
    else u.cov0 = 1,u.cov1 = 0;
    if(k) u.all1 = 1,u.all0 = 0;
    else u.all0 = 1,u.all1 = 0;
}

void changetag(Node &u,ll l,ll r)
{
    if(u.all0) u.all1 = 1,u.all0 = 0;
    else if(u.all1) u.all0 = 1,u.all1 = 0;
    u.tag ^= 1;
}

void pushdown(int u,ll l,ll r)
{
    if(!ls[u]) ls[u] = init(++idx);
    if(!rs[u]) rs[u] = init(++idx);
    auto &root = tr[u],&left = tr[ls[u]],&right = tr[rs[u]];
    ll mid = l + r >> 1ll;
    if(root.cov0||root.cov1)
    {
        int k = 0;if(root.cov1) k = 1;
        changecov(left,k,l,mid);
        changecov(right,k,mid+1,r);
        root.cov0 = root.cov1 = 0;
    }
    if(root.tag)
    {
        changetag(left,l,mid);
        changetag(right,mid+1,r);
        root.tag = 0;
    }
}

void modify(int &u, ll l, ll r, ll L, ll R,int ty,int k) 
{
    if(R<l||L>r) return ;
    if(!u) u = init(++idx);
    if(L <= l && R >= r) {
        if(ty==1) 
        {
            changecov(tr[u],k,l,r);
            if(k) tr[u].cov1 = 1,tr[u].cov0 = 0;
            else tr[u].cov0 = 1,tr[u].cov1 = 0;
        }
        else changetag(tr[u],l,r);
        return ;
    }
    pushdown(u,l,r);
    ll mid = l + r >> 1ll;
    modify(ls[u], l, mid, L, R, ty, k);modify(rs[u], mid + 1, r, L, R, ty, k);
    pushup(u);
}

ll query(int u,ll l,ll r)
{
    if(!u) return l;
    if(l==r) return l;
    pushdown(u,l,r);
    ll mid = l + r >> 1ll;
    if(!tr[ls[u]].all1) return query(ls[u],l,mid);
    return query(rs[u],mid+1,r);
}

int main()
{
    ios;
    int n;cin>>n;
    while(n--)
    {
        ll op,l,r;cin>>op>>l>>r;
        if(op==1) modify(root,1,inf,l,r,1,1);
        else if(op==2) modify(root,1,inf,l,r,1,0);
        else modify(root,1,inf,l,r,2,0);
        cout<<query(root,1,inf)<<"\n";
    }   
    return 0;
}
posted @ 2022-11-03 17:28  艾特玖  阅读(44)  评论(0)    收藏  举报