zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    windows 乱码之 gbk 与 cp936
    jdcli 在命令行反编译jar包
    建议博客园向独立博客提供发布到首页的服务
    IsByRef在什么情况下为true?
    Hibernate里自定义UserType时取不到值的问题
    解决安装Visual Studio 2010 SP1时被NDP40KB2468871.exe补丁卡死以及mscorsvw.exe进程CPU占用率高的问题
    FROM WAS7/JDK5 TO WAS6/JDK4
    C++山寨C#中的DataTable
    程序员的自我修养读书笔记
    Web开发之路
  • 原文地址:https://www.cnblogs.com/gzy-cjoier/p/7150768.html
Copyright © 2011-2022 走看看