题意:一个无限长的序列,q次操作,有三种操作:
1 l r : 将区间[l, r]设为1
2 l r : 将区间[l, r]设为0
3 l r : 将区间[l, r]的数反转(0变1, 1变0)
每次操作后输出最小的为0的位置下标
(q <= 1e5, l, r <= 1e18)
思路:前两个操作就是基础的线段数区间设置操作,关键是操作3怎么实现,线段树每个节点维护的是区间和,如果我们将它的区间反转,那和就变成了区间长度-原区间和。这样更新每个节点,就实现了反转。因为l, r比较大,所以需要离散化,因为可能的答案只是l 或 r+1所以只需要将它俩离散化,还有1可能为答案,还需要把1离散化。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5+5;
int n, treeSum[maxn*4], lazy[maxn*4], flag[maxn*4];
ll a[maxn], aa[maxn], Hash[maxn];
struct node
{
int t;
ll l, r;
}op[maxn];
void build(int root, int l, int r)
{
treeSum[root] = 0;
flag[root] = 0;
lazy[root] = -1;
if(l == r) return ;
int mid = (l+r)/2;
build(root*2, l, mid);
build(root*2+1, mid+1, r);
}
void pushUp(int root)
{
treeSum[root] = treeSum[root*2]+treeSum[root*2+1];
}
void pushDown(int root, int l, int r)
{
int mid = (l+r)/2;
if(lazy[root] != -1) //区间设值标记下放,同时去除反转标记
{
lazy[root*2] = lazy[root*2+1] = lazy[root];
treeSum[root*2] = (mid-l+1)*lazy[root];
treeSum[root*2+1] = (r-mid)*lazy[root];
flag[root*2] = flag[root*2+1] = 0;
lazy[root] = -1;
}
if(flag[root]) //下放反转标记
{
flag[root*2] ^= 1;
flag[root*2+1] ^= 1;
treeSum[root*2] = (mid-l+1)-treeSum[root*2];
treeSum[root*2+1] = (r-mid)-treeSum[root*2+1];
flag[root] = 0;
}
}
void Set(int root, int l, int r, int i, int j, int val)
{
if(i <= l && j >= r)
{
treeSum[root] = (r-l+1)*val;
lazy[root] = val;
flag[root] = 0;
return ;
}
pushDown(root, l, r);
int mid = (l+r)/2;
if(i <= mid) Set(root*2, l, mid, i, j, val);
if(j > mid) Set(root*2+1, mid+1, r, i, j, val);
pushUp(root);
}
void Reverse(int root, int l, int r, int i, int j)
{
if(i <= l && j >= r)
{
treeSum[root] = (r-l+1)-treeSum[root];
flag[root] ^= 1;
return ;
}
pushDown(root, l, r);
int mid = (l+r)/2;
if(i <= mid) Reverse(root*2, l, mid, i, j);
if(j > mid) Reverse(root*2+1, mid+1, r, i, j);
pushUp(root);
}
ll Query(int root, int l, int r)
{
if(l == r) return l;
int mid = (l+r)/2;
pushDown(root, l, r);
if(treeSum[root*2] < mid-l+1) return Query(root*2, l, mid);
else return Query(root*2+1, mid+1, r);
}
int main(void)
{
while(cin >> n)
{
int cnt = 1;
for(int i = 1; i <= n; i++)
{
scanf("%d%I64d%I64d", &op[i].t, &op[i].l, &op[i].r);
op[i].r++;
a[cnt] = aa[cnt] = Hash[cnt] = op[i].l;
cnt++;
a[cnt] = aa[cnt] = Hash[cnt] = op[i].r;
cnt++;
}
a[cnt] = aa[cnt] = Hash[cnt] = 1;
cnt++;
cnt--;
sort(Hash+1, Hash+1+cnt);
int d = unique(Hash+1, Hash+1+cnt)-Hash-1;
for(int i = 1; i <= cnt; i++)
aa[i] = lower_bound(Hash+1, Hash+1+d, a[i])-Hash;
build(1, 1, d);
for(int i = 1; i <= n; i++)
{
int cmd = op[i].t;
int l = aa[(i-1)*2+1];
int r = aa[i*2]-1; //注意要-1
if(cmd == 1)
Set(1, 1, d, l, r, 1);
else if(cmd == 2)
Set(1, 1, d, l, r, 0);
else
Reverse(1, 1, d, l, r);
printf("%I64d\n", Hash[Query(1, 1, d)]);
}
}
return 0;
}