卧薪尝胆,厚积薄发。
      
    
            MEX Queries
        
        
        Description:
给你一个无限长的数组,初始的时候都为
$0$
,操作
$1$
是把给定区间清零,操作
$2$
是把给定区间设为
$1$
,操作
$3$
把给定区间反转。每次操作后要输出最小位置的
$0$
。 
$1\le N \le 10^5$
 
$1\le l,r \le 10^{18}$
Solution:
先将范围离散化,将每个出现的数据保留下来,连续的缩成一个块,因为最小值可能在那里出现,区间置一置零打标记即可,但区间反转标记不能随便下放,因为子节点可能已经打了其他的标记,直接给子节点打反转标记会有标记丢失,于是在下放时子节点标记为
$2-$
标记,这样原来置一的置零,原来置零的置一,原来反转的不再反转,就可以下放了。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
using namespace std;
#define MAXN 600010
int n;
typedef long long ll;
struct change
{
	ll l,r;
	int type;
}c[MAXN];
ll s[MAXN];
int tot = 0;
map<ll,int> to;
ll fr[MAXN];
struct node
{
	int lc,rc,sum;
	int tag;
	node(){tag = -1;}
}t[MAXN << 1];
int ptr = 0;
int newnode(){return ++ptr;}
int root;
#define mid ((l + r) >> 1)
void build(int &rt,int l,int r)
{
	rt = newnode();
	if(l == r)return;
	build(t[rt].lc,l,mid);
	build(t[rt].rc,mid + 1,r);
	return;
}
void pushdown(int rt,int l,int r)
{
	if(t[rt].tag == -1)return;
	if(t[rt].tag == 0)
	{
		t[t[rt].lc].tag = t[t[rt].rc].tag = 0;
		t[t[rt].lc].sum = t[t[rt].rc].sum = 0;
	}
	if(t[rt].tag == 1)
	{
		t[t[rt].lc].tag = t[t[rt].rc].tag = 1;
		t[t[rt].lc].sum = (mid - l + 1);t[t[rt].rc].sum = (r - mid);
	}
	if(t[rt].tag == 2)
	{
		t[t[rt].lc].tag = 1 - t[t[rt].lc].tag;
		t[t[rt].rc].tag = 1 - t[t[rt].rc].tag;
		t[t[rt].lc].sum = (mid - l + 1) - t[t[rt].lc].sum;
		t[t[rt].rc].sum = (r - mid) - t[t[rt].rc].sum;
	}
	t[rt].tag = -1;
	return;
}
void add(int rt,int L,int R,int l,int r)
{
	pushdown(rt,l,r);
	if(L <= l && r <= R)
	{
		t[rt].sum = (r - l + 1);
		t[rt].tag = 1;
		return;
	}
	if(L <= mid)add(t[rt].lc,L,R,l,mid);
	if(R > mid)add(t[rt].rc,L,R,mid + 1,r);
	t[rt].sum = t[t[rt].lc].sum + t[t[rt].rc].sum;
	return;
}
void del(int rt,int L,int R,int l,int r)
{
	pushdown(rt,l,r);
	if(L <= l && r <= R)
	{
		t[rt].sum = 0;
		t[rt].tag = 0;
		return;
	}
	if(L <= mid)del(t[rt].lc,L,R,l,mid);
	if(R > mid)del(t[rt].rc,L,R,mid + 1,r);
	t[rt].sum = t[t[rt].lc].sum + t[t[rt].rc].sum;
	return;
}
void rev(int rt,int L,int R,int l,int r)
{
	pushdown(rt,l,r);
	if(L <= l && r <= R)
	{
		t[rt].tag = 2;
		t[rt].sum = (r - l + 1) - t[rt].sum;
		return;
	}
	if(L <= mid)rev(t[rt].lc,L,R,l,mid);
	if(R > mid)rev(t[rt].rc,L,R,mid + 1,r);
	t[rt].sum = t[t[rt].lc].sum + t[t[rt].rc].sum;
	return;
}
ll query(int rt,int l,int r)
{
	if(l == r)return fr[l];
	pushdown(rt,l,r);
	if(t[t[rt].lc].sum == (mid - l + 1))return query(t[rt].rc,mid + 1,r);
	else return query(t[rt].lc,l,mid);
}
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)
	{
		scanf("%d%I64d%I64d",&c[i].type,&c[i].l,&c[i].r);
		s[++tot] = c[i].l;s[++tot] = c[i].r;
	}
	sort(s + 1,s + 1 + tot);
	tot = 0;
	ll cur = 0;
	for(int i = 1;i <= 2 * n;++i)
	{
		if(s[i] == s[i - 1])continue;
		if(s[i] != cur + 1){++tot;fr[tot] = cur + 1;}
		to[s[i]] = ++tot;cur = s[i];fr[tot] = s[i];
	}
	++tot;fr[tot] = cur + 1;
	build(root,1,tot);
	for(int i = 1;i <= n;++i)
	{
		if(c[i].type == 1)
		{
			add(root,to[c[i].l],to[c[i].r],1,tot);
		}
		if(c[i].type == 2)
		{
			del(root,to[c[i].l],to[c[i].r],1,tot);
		}
		if(c[i].type == 3)
		{
			rev(root,to[c[i].l],to[c[i].r],1,tot);
		}//pt(root,1,tot);puts("");
		printf("%I64d\n",query(root,1,tot));
	}
	return 0;
}
 In tag:
数据结构-线段树
          In tag:
数据结构-线段树 
          
        
        Copyright © 2020
        
          wjh15101051
        
      
      ღゝ◡╹)ノ♡
     Date: Thu Jul 12 00:14:31 CST 2018
          Date: Thu Jul 12 00:14:31 CST 2018
           In Category:
          In Category:
           
         Timeline
            Timeline
           About
            About
           Toolbox
            Toolbox
           Friends
              Friends