[Codeforces]817F. MEX Queries 离散化+线段树维护

[Codeforces]817F. MEX Queries

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 

1 3 4 
3 1 6 
2 1 3 
output 



input 

1 1 3 
3 5 6 
2 4 4 
3 1 6 
output 




Note 
Here are contents of the set after each query in the first example: 
{3, 4} — the interval [3, 4] is added 
{1, 2, 5, 6} — numbers {3, 4} from the interval [1, 6] got deleted and all the others are added 
{5, 6} — numbers {1, 2} got deleted

题意

给你一个无限长的数组,初始的时候都为0,操作1是把给定区间清零,操作2是把给定区间设为1,操作3把给定区间反转。每次操作后要输出最小位置的0。

题解

看到数据范围n<=10^5,结合题意可以考虑使用线段树维护对区间的修改操作。但是l,r<=10^18,所以首先要离散化一下。在使用线段树维护的时候,节点维护该区间数相加的总和。对于操作1和操作2,我们分别赋值为1和0,对于操作3,我们把区间反转,那么新的区间和就是区间的长度减去原来的区间和。然后每次查询最小位置的0,只需要看一下左儿子所代表的区间是否小于这个区间的长度,如果是就在左儿子,否则就在右儿子查找。

题目细节

这道题有很多坑人的点,首先,在离散化的时候必须把1也加上,因为答案可能为1;线段树在下传标记时要注意顺序;记录原来信息的数组必须得开long long,空间一定要开够。

代码

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<map>
  8 using namespace std;
  9 #define ll long long
 10 #define REP(i,a,b) for(register int i=(a),_end_=(b);i<=_end_;i++)
 11 #define DREP(i,a,b) for(register int i=(a),_end_=(b);i>=_end_;i--)
 12 #define EREP(i,a) for(register int i=start[(a)];i;i=e[i].next)
 13 inline int read()
 14 {
 15     int sum=0,p=1;char ch=getchar();
 16     while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
 17     if(ch=='-')p=-1,ch=getchar();
 18     while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
 19     return sum*p;
 20 }
 21 const int maxn=150020;
 22 
 23 map <ll,int> mp;
 24 int m,cnt;
 25 ll s[maxn*3],n;
 26 
 27 struct qu {
 28     ll l,r;
 29     int type;
 30 }a[maxn];
 31 
 32 struct node {
 33     int s,lz,id;//s记录区间和,lz为懒标记,id维护区间是否反转
 34 }c[maxn*10];
 35 
 36 #define lc (o<<1)
 37 #define rc (o<<1 | 1)
 38 #define left lc,l,mid
 39 #define right rc,mid+1,r
 40 
 41 inline void make_tree(int o,int l,int r)
 42 {
 43     c[o].s=0;c[o].lz=-1;c[o].id=0;
 44     if(l==r)return;
 45     int mid=(l+r)>>1;
 46     make_tree(left);
 47     make_tree(right);
 48 }
 49 
 50 void maintain(int o,int l,int r)
 51 {
 52     c[o].s=c[lc].s+c[rc].s;
 53 }
 54 
 55 void pushdown(int o,int l,int r)
 56 {
 57     int mid=(l+r)>>1;
 58     if(c[o].lz!=-1)//下传懒标记,同时将儿子节点的反转标记清0
 59     {
 60         c[lc].lz=c[rc].lz=c[o].lz;
 61         c[lc].s=(mid-l+1)*c[o].lz;
 62         c[rc].s=(r-mid)*c[o].lz;
 63         c[lc].id=c[rc].id=0;
 64         c[o].lz=-1;
 65     }
 66     if(c[o].id)//将儿子节点的反转标记也反转,同时维护儿子的区间和
 67     {
 68         c[lc].id^=1;
 69         c[rc].id^=1;
 70         c[lc].s=(mid-l+1)-c[lc].s;
 71         c[rc].s=(r-mid)-c[rc].s;
 72         c[o].id=0;
 73     }
 74 }
 75 
 76 inline void updates(int ql,int qr,int x,int o,int l,int r)
 77 {
 78     pushdown(o,l,r);
 79     if(ql==l && r==qr)//把区间覆盖为x
 80     {
 81         c[o].s=(r-l+1)*x;
 82         c[o].lz=x;
 83         c[o].id=0;
 84         return;
 85     }
 86     int mid=(l+r)>>1;
 87     if(ql>mid)
 88     {
 89         updates(ql,qr,x,right);
 90     }
 91     else if(qr<=mid)
 92     {
 93         updates(ql,qr,x,left);
 94     }else
 95     {
 96         updates(ql,mid,x,left);
 97         updates(mid+1,qr,x,right);
 98     }
 99     maintain(o,l,r);
100 }
101 
102 inline void updatex(int ql,int qr,int o,int l,int r)
103 {
104     pushdown(o,l,r);
105     if(ql==l && r==qr)//把区间反转
106     {
107         c[o].s=(r-l+1)-c[o].s;
108         c[o].id^=1;
109         return;
110     }
111     int mid=(l+r)>>1;
112     if(ql>mid)
113     {
114         updatex(ql,qr,right);
115     }
116     else if(qr<=mid)
117     {
118         updatex(ql,qr,left);
119     }else
120     {
121         updatex(ql,mid,left);
122         updatex(mid+1,qr,right);
123     }
124     maintain(o,l,r);
125 }
126 
127 void init()
128 {
129     m=read();
130     REP(i,1,m)
131     {
132         cin>>a[i].type>>a[i].l>>a[i].r;
133         a[i].r++;
134         s[++cnt]=a[i].l;
135         s[++cnt]=a[i].r;
136     }
137     s[++cnt]=1;//答案中可能会有1,必须加上
138     sort(s+1,s+cnt+1);
139     n=unique(s+1,s+cnt+1)-(s+1);
140     REP(i,1,n)mp[s[i]]=i;
141     make_tree(1,1,n);
142 }
143 
144 void query(int o,int l,int r)
145 {
146     if(l==r)
147     {
148         cout<<s[l]<<endl;
149         return;
150     }
151     int mid=(l+r)>>1;
152     pushdown(o,l,r);
153     if(c[lc].s<mid-l+1)
154         query(left);
155     else query(right);
156 }
157 
158 void doing()
159 {
160     REP(i,1,m)
161     {
162         int type=a[i].type,l=mp[a[i].l],r=mp[a[i].r]-1;
163         if(type==1)
164         {
165             updates(l,r,1,1,1,n);
166         }
167         else if(type==2)
168         {
169             updates(l,r,0,1,1,n);
170         }else
171         {
172             updatex(l,r,1,1,n);
173         }
174         query(1,1,n);
175     }
176 }
177 
178 int main()
179 {
180     init();
181     doing();
182     return 0;
183 }

 

posted @ 2017-07-11 15:25  Deadecho  阅读(797)  评论(3编辑  收藏  举报