F. MEX Queries
分析
不得不说,题目不算难。但是非常考验选手的基础。我会把我出的问题放出到最后,给大家一些错误提示。
我们使用动态开点维护权值线段树。
我们先来看四个操作。
1.把 [l,r]
中在集合中没有出现过的数添加到集合中。
直接区间覆盖,将区间[l,r]
区间覆盖为1。加一个懒标记cov1
。
2.把 [l,r]
中在集合中出现过的数删除。
直接区间覆盖,将区间[l,r]
区间覆盖0。加一个懒标记cov0
。
3.把 [l,r]
中在集合中没有出现过的数添加到集合中,并且将出现过的数删除。
直接区间取反。加一个懒标记tag
。
4.询问集合中最小的没有出现过的正整数
我们添加两个标记,all0
,all1
,来统计区间是否全部都为0
或1
。
我们关于树中结点的设计方面就是
struct Node
{
bool tag,all1,all0,cov0,cov1;
}tr[N*200];
int ls[N*200],rs[N*200];
然后就是常规的pushdown
,pushup
什么的了。这点不说了。
一些细节
我直接给大家展示我结构体的一步步变化。
除了最后答案中可以乘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;
}
标签:int,ll,all0,tr,all1,Queries,cov1,MEX
From: https://www.cnblogs.com/aitejiu/p/16855239.html