mex (离散化+线段树)

Time Limit: 3000 ms   Memory Limit: 256 MB

Description

  给你一个无限长的数组,初始的时候都为0,有3种操作:

  操作1是把给定区间$[l,r]$设为1,

  操作2是把给定区间$[l,r]$设为0,

  操作3把给定区间$[l,r]$0,1反转。

  一共n个操作,每次操作后要输出最小位置的0。

Input

  第一行一个整数n,表示有n个操作

  接下来n行,每行3个整数op,l,r表示一个操作

Output

  共n行,一行一个整数表示答案

Sample Input

Sample Output

3
1 3 4
3 1 6
2 1 3
1
3
1

HINT

  对于30%的数据$1\le n\le 10^3,1\le l\le r\le 10^{18}$

  对于100%的数据$1\le n\le 10^5,1\le l\le r\le 10^{18}$


题解

  离散化操作区间:

  首先看到$1\le l\le r\le 10^{18}$的范围,第一反应离散化。

    这题的离散化是非常讲究的,我们不能只把每个区间操作的两端点提取出来离散化(我就是这么干的,其他部分都是对的,结果眼睁睁地没法输出),因为这样无法考虑到区间之间的点,如下图:

  

  考虑到答案的位置,答案应该只可能出现在某一段操作区间右端点的右边一位,于是我们在离散一个操作区间$l,r$的同时,把$r+1$也离散化掉。操作并不涉及到$r+1$,仅仅是为了输出答案的正确和可行性。

  实现修改操作:

    看到熟悉的区间操作,当然要想想线段树啦。

     这里采用两棵线段树的写法实现3种操作,当然也有一棵线段树搞定的写法。

     两棵线段树$A,B$,都先按照离散化的规模建好,以离散化端点编号为索引。$A$记录$0$的信息,$B$记录$1$的信息。

     线段树维护的信息是:$0$或$1$最左出现的位置。

     第1个操作:将$A$的相应区间的信息清空(设置成最大值,因为不存在$0$了),将$B$的相应区间的信息填充(设置成区间的左端点位置),并打上清空或填充标记。日后记得下传。

     第2个操作:与第1个操作完全相反。

       第3个操作:将$A$的相应区间节点和$B$的相应区间节点对调。

  输出:

    询问$A$中的最小值位置,输出离散化前的原值即可。可以发现这个点一定是某个区间的$r$再$+1$。

  时间复杂度$O(n lg n)$,空间复杂度$O(n)$。



  1 #include <cstdio>
  2 #include <algorithm>
  3 #define min(a,b) (a<b?a:b)
  4 using namespace std;
  5 typedef long long ll;
  6 const int N=1e5+10;
  7 ll INF=1000000000000000001;
  8 int n,lshtot,opt[N][3],total;
  9 ll inp[N][3],lis[N*3],minloc,maxloc,orival[N*3];
 10 void lshAndfill(){
 11     sort(lis+1,lis+1+lshtot);
 12     total=unique(lis+1,lis+1+lshtot)-lis-1;
 13     for(int i=1;i<=total;i++) orival[i]=lis[i];
 14     orival[total+1]=INF;
 15     for(int i=1;i<=n;i++){
 16         opt[i][0]=inp[i][0];
 17         opt[i][1]=lower_bound(lis+1,lis+1+total,inp[i][1])-lis;
 18         opt[i][2]=lower_bound(lis+1,lis+1+total,inp[i][2])-lis;
 19     }
 20 }
 21 struct Seg{
 22     int cnt,root[2],sz,ch[N*13][2],mark[N*13];
 23     ll info[N*13];
 24     void build(int Size){
 25         sz=Size;
 26         _build(root[0],1,sz,true);
 27         _build(root[1],1,sz,false);
 28     }
 29     void _build(int &u,int l,int r,bool isfill){
 30         if(!u) u=++cnt;
 31         mark[u]=-1;
 32         if(l==r){
 33             if(isfill) info[u]=l;
 34             else info[u]=total+1;
 35             return;
 36         }
 37         int mid=(l+r)>>1;
 38         _build(ch[u][0],l,mid,isfill);
 39         _build(ch[u][1],mid+1,r,isfill);
 40         pushup(u);
 41     }
 42     inline void pushup(int u){
 43         info[u]=min(info[ch[u][0]],info[ch[u][1]]);
 44     }
 45     inline void pushdown(int u,int l,int r){
 46         int lc=ch[u][0],rc=ch[u][1];
 47         if(mark[u]==-1) return;
 48         mark[lc]=mark[rc]=mark[u];
 49         if(mark[u]==0)
 50             info[lc]=info[rc]=total+1;
 51         else{
 52             info[lc]=l;
 53             info[rc]=(l+r)/2+1;
 54         }
 55         mark[u]=-1;
 56     }
 57     void setSeg(int flag,int l,int r){
 58         _setSeg(root[0^flag],root[1^flag],1,sz,l,r);
 59     }
 60     void _setSeg(int u1,int u2,int l,int r,int L,int R){
 61         if(L<=l&&r<=R){
 62             info[u1]=total+1;
 63             info[u2]=l;
 64             mark[u1]=0; mark[u2]=1;
 65             return;
 66         }
 67         pushdown(u1,l,r);
 68         pushdown(u2,l,r);
 69         int mid=(l+r)>>1;
 70         if(L<=mid) _setSeg(ch[u1][0],ch[u2][0],l,mid,L,R);
 71         if(mid<R) _setSeg(ch[u1][1],ch[u2][1],mid+1,r,L,R);
 72         pushup(u1);
 73         pushup(u2);
 74     }
 75     void swapSeg(int l,int r){_swapSeg(root[0],root[1],1,sz,l,r);}
 76     void _swapSeg(int &u1,int &u2,int l,int r,int L,int R){
 77         if(L<=l&&r<=R){
 78             swap(u1,u2);
 79             return;
 80         }
 81         pushdown(u1,l,r);
 82         pushdown(u2,l,r);
 83         int mid=(l+r)>>1;
 84         if(L<=mid) _swapSeg(ch[u1][0],ch[u2][0],l,mid,L,R);
 85         if(mid<R) _swapSeg(ch[u1][1],ch[u2][1],mid+1,r,L,R);
 86         pushup(u1);
 87         pushup(u2);
 88     }
 89     inline ll getMin(int x){return info[root[x]];}
 90 }seg;
 91 int main(){
 92     scanf("%d",&n);
 93     minloc=-1;
 94     for(int i=1;i<=n;i++){
 95         scanf("%lld%lld%lld",&inp[i][0],&inp[i][1],&inp[i][2]);
 96         lis[++lshtot]=inp[i][1];
 97         lis[++lshtot]=inp[i][2];
 98         lis[++lshtot]=inp[i][2]+1;
 99         if(minloc==-1) minloc=min(inp[i][1],inp[i][2]);
100         else minloc=min(minloc,min(inp[i][1],inp[i][2]));
101     }
102     lshAndfill();
103     seg.build(total);
104     for(int i=1;i<=n;i++){
105         if(minloc>1){
106             printf("1\n");
107             continue;
108         }
109         if(opt[i][0]<=2)
110             seg.setSeg(opt[i][0]==2,opt[i][1],opt[i][2]);
111         else
112             seg.swapSeg(opt[i][1],opt[i][2]);
113         printf("%lld\n",orival[seg.getMin(0)]);
114     }
115     return 0;
116 }

奇妙代码

时间: 2024-08-26 12:47:49

mex (离散化+线段树)的相关文章

poj 2528 Mayor&#39;s posters【离散化+线段树】

题目:poj 2528 Mayor's posters 题意:给一个长度非常长的墙上贴长度为ai的海报,由于有的会覆盖掉,求最后能看见的海报个数. 分析:题目和POJ2777 一模一样,方法也一样,只不过这个要离散化,其次要数组开大一点.至少2倍. 离散化的时候用了C++的 pair 类,还是比较好用的. 代码: #include <iostream> #include <algorithm> #include <utility> #include <cstrin

POJ 2299 离散化线段树

点击打开链接 Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 40827   Accepted: 14752 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by

南阳理工 题目9:posters(离散化+线段树)

posters 时间限制:1000 ms  |  内存限制:65535 KB 难度:6 描述 The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally deci

Mayor&#39;s posters(离散化线段树)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 54067   Accepted: 15713 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

POJ 2528 Mayor&#39;s posters(离散化线段树)

Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for

bnu36905 Nested Segments 离散化+线段树

bnu36905 Nested Segments 离散化+线段树区间更新 也可以用离散化+set(或双向链表) #include <cstdio> #include <ctime> #include <cstdlib> #include <cstring> #include <queue> #include <string> #include <set> #include <stack> #include &l

POJ 2528 Mayor&amp;#39;s posters 离散化+线段树

题目大意:给出一些海报和贴在墙上的区间.问这些海报依照顺序贴完之后,最后能后看到多少种海报. 思路:区间的范围太大,然而最多仅仅会有10000张海报,所以要离散化. 之后用线段树随便搞搞就能过. 关键是离散化的方法,这个题我时隔半年才A掉,之前一直就TTT,我还以为是线段树写挂了. 当我觉得我自己的水平这样的水线段树已经基本写不挂的时候又写了这个题,竟然还是T. 后来我对照别人的代码,才发现是我的离散化写渣了. 以下附AC代码(79ms),这个离散化写的比較优雅.时间也非常快,以后就这么写了.

POJ 2528 Mayor&#39;s posters (离散化 + 线段树)

强烈不推荐在POJ做这道题!!! 强烈不推荐在POJ做这道题!!! 强烈不推荐在POJ做这道题!!! 推荐去UVA 10587 或 SCU 2249 POJ的数据比较水且可能有错,一些本来错误的数据但可以水过,以及在UVA与SCU同样题目都能AC的程序在POJ莫名WA了. 建议写完程序后跑下这组数据: 1 3 1 10 1 3 6 10 好多题解的答案是2,但答案明显是3,这是因为每个数字其实表示的是一个单位长度,并非一个点 , 这就会导致像这样的区间: 1-10 1-4 5-10 1-10 1

【POJ】2528 Mayor&#39;s posters ——离散化+线段树

Mayor's posters Time Limit: 1000MS    Memory Limit: 65536K Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city

Mex(线段树的巧妙应用)

题目要求求某段区间第一个没有出现的数(0,1,2,3....) ,对于所有的区间,我们把这样的数加起来最后得到一个结果. 首先,我们要求出这样的数,然后还得列举出所有的区间,复杂度太大了. 换种思路,我们定住L,是不是一次性能求出所有的R所得出的结果,这就用到线段树的性质了,因为在移动L的过程中,移一步只变化一个数,那么就可以用线段树进行维护. 首先求出[1,R] 以1为左端的所有区间的情况,记录每个点也就是1到那个点的这段区间值sum[i],以这个值建一颗树,那么在L向前移动的时候,每次丢掉一