[Codeforces 817F] Mex Queries 模型构建与转化+线段树

F. MEX Queries
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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  ≥ 1) integer number which is not presented in the set.

Input

The first line contains one integer number n (1 ≤ n ≤ 105).

Next n lines contain three integer numbers t, l, r (1 ≤ t ≤ 3, 1 ≤ l ≤ r ≤ 1018) — type of the query, left and right bounds.

Output

Print MEX of the set after each query.

Examples
input
3
1 3 4
3 1 6
2 1 3
output
1
3
1
input
4
1 1 3
3 5 6
2 4 4
3 1 6
output
4
4
4
1
Note

Here are contents of the set after each query in the first example:

  1. {3, 4} — the interval [3, 4] is added
  2. {1, 2, 5, 6} — numbers {3, 4} from the interval [1, 6] got deleted and all the others are added

  1. {5, 6} — numbers {1, 2} got deleted


题解:首先,l,r<=10^18,所以考虑离散化,
           但是离散化需要考虑对答案的影响,
           经过分析观察,可以发现,答案只有可能是1,l,r+1,
           所以可以按照l,r+1把所有数字离散为(2n+1)个数(注意:1可能也是答案)
           然后就可以用数据结构维护-------->线段树,
            线段树上,每个节点代表一段区间,
            而相同节点所代表的区间在整个过程中在与不在集合中这个01状态是相同的。
           对于每个节点,可以维护0,1值表示这个节点是否在集合中,
            remove操作就是将l-r区间赋值为0, add操作就是将l-r区间赋值为1,
            而invert操作就是区间取xor,通过重新计算区间和值进行实现,
            然后每次询问就是查询最左边的0的位置,可以通过维护区间和值进行查询.
            时间复杂度:O(qlogq),本题的核心在于想到用线段树的一个节点维护一个连续区间.
Code:
这道题交了6发才过,有几点需要注意,
首先,线段树下传标记时,父亲节点的优先级总是高于儿子节点,会产生覆盖,
同一层内维护多个lazy_tag时需要注意它们之间的先后关系与优先级---------->因为这个3次WA on 7
然后,线段树4倍空间,缺一点都不行,
在本题中,有极限200002个节点,线段树开800000会GG------------------------->1次RE on 11
最后就是输出时不能想当然%d,这里是long long----------------------------------->1次WA on 12
这种小清新题博主还要交6发才能A,还是太菜辣!
#include <bits/stdc++.h>
#define ll long long
using namespace std;
struct query
{int opt;
ll l,r;
}q[100005];
ll x[200005];
int cnt=0;
map <ll,int> mp;
struct tree
{int l,r,tag,sum,rev;
}t[1000005];
void build(int pos,int l,int r)
{t[pos].l=l;
t[pos].r=r;
t[pos].tag=-1;
t[pos].sum=0;
t[pos].rev=0;
if (l==r) {return;}
int mid=(l+r)>>1;
build(pos*2,l,mid);
build(pos*2+1,mid+1,r);
}
inline void pd(int pos)
{if (t[pos].tag!=-1)
{t[pos*2].tag=t[pos].tag;
t[pos*2+1].tag=t[pos].tag;
t[pos*2].sum=t[pos].tag*(t[pos*2].r-t[pos*2].l+1);
t[pos*2+1].sum=t[pos].tag*(t[pos*2+1].r-t[pos*2+1].l+1);
t[pos*2].rev=0;t[pos*2+1].rev=0;
t[pos].tag=-1;
}
if (t[pos].rev)
{t[pos*2].rev^=t[pos].rev;
t[pos*2+1].rev^=t[pos].rev;
t[pos*2].sum=(t[pos*2].r-t[pos*2].l+1)-t[pos*2].sum;
t[pos*2+1].sum=(t[pos*2+1].r-t[pos*2+1].l+1)-t[pos*2+1].sum;
t[pos].rev=0;
}
}
inline void upd(int pos)
{t[pos].sum=t[pos*2].sum+t[pos*2+1].sum;}
void qinding(int pos,int l,int r,int val)
{pd(pos);
if (t[pos].l==l&&t[pos].r==r)
{t[pos].sum=val*(r-l+1);
t[pos].tag=val;t[pos].rev=0;
return;
}
int mid=(t[pos].l+t[pos].r)>>1;
if (l>=mid+1) 
{qinding(pos*2+1,l,r,val);}
else
{if (r<=mid)
{qinding(pos*2,l,r,val);}
else
{qinding(pos*2,l,mid,val);
qinding(pos*2+1,mid+1,r,val);
}
}
upd(pos);
}
void inver(int pos,int l,int r)
{pd(pos);
if (t[pos].l==l&&t[pos].r==r)
{t[pos].sum=(r-l+1)-t[pos].sum;t[pos].rev^=1;return;}
int mid=(t[pos].l+t[pos].r)>>1;
if (l>=mid+1) 
{inver(pos*2+1,l,r);}
else
{if (r<=mid)
{inver(pos*2,l,r);}
else
{inver(pos*2,l,mid);
inver(pos*2+1,mid+1,r);
}
}
upd(pos);
}
int ask(int pos)
{if (t[pos].l==t[pos].r) {return t[pos].l;}
int mid=(t[pos].l+t[pos].r)>>1;
pd(pos);
if (t[pos*2].sum==t[pos*2].r-t[pos*2].l+1)
{return ask(pos*2+1);}
return ask(pos*2);
}
int main (){
	int i,qr;
	scanf ("%d",&qr);
	for (i=1;i<=qr;i++)
	{scanf ("%d%lld%lld",&q[i].opt,&q[i].l,&q[i].r);
	x[++cnt]=q[i].l;x[++cnt]=q[i].r+1;
	}
	x[++cnt]=1ll;
	x[++cnt]=1000000000000000005ll;
	sort(x+1,x+cnt+1);
	cnt=unique(x+1,x+cnt+1)-x-1;
	for (i=1;i<=cnt;i++)
	{mp[x[i]]=i;}
	build(1,1,cnt);
	for (i=1;i<=qr;i++)
	{int lc=mp[q[i].l],rc=mp[q[i].r+1]-1;
	if (q[i].opt==1)
	{qinding(1,lc,rc,1);}
	if (q[i].opt==2)
	{qinding(1,lc,rc,0);}
	if (q[i].opt==3)
	{inver(1,lc,rc);}
	printf ("%lld\n",x[ask(1)]);
	}
	return 0;
}
	
	
	


	


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值