码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces - 817F. MEX Queries

时间:2019-08-10 11:37:47      阅读:82      评论:0      收藏:0      [点我收藏+]

标签:www   节点   nbsp   离线   void   efi   stream   ||   open   

题目

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

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

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

操作3把给定区间[l,r][l,r] 0,1反转。
l,r<=1018
一共n(n<=105)个操作,每次操作后要输出最小位置的0。

解法

看到维护区间,想到线段树。

看到数据范围,想到把操作离线然后离散化。

然后再yy一下合并状态:

每个节点维护两个信息:

min0表示该区间最小位置的0,初始值为l (当时错在了这里)。

min1表示该区间最小位置的1,初始值为inf。

合并时左右取最小即可

操作

  1. min0=inf,min1=l
  2. min0=l,min1=inf
  3. 交换min0,min1

通过懒标记维护。

一些细节问题

  • 离散化时要把r+1也一同离散化,否则 (r0,l1)这段区间会遗失。(当时错在了这里*2)
  • pushdown的时候可能同时会有反转和修改操作,为了防止顺序出错,要做点处理(当时错在了这里*3)
    1. 反转标记在前,修改操作在后:可以直接无视掉反转标记。所以要在打标记前清除反转标记。
    2. 反转标记在后,修改操作在前:必须先处理修改操作。所以pushdown函数里修改要写在反转的前面
  • 数组要开n*3*4(每个操作最多有三个数,线段树空间要*4)(当时错在了这里*4)

代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
#define N 5000000
#define int long long
#define root 1,1,maxn
#define mid (l+r)/2
#define ls id*2
#define rs id*2+1
#define lc ls,l,mid,tl,tr 
#define rc rs,mid+1,r,tl,tr
#define inf 4611686018427387904
int min0[N],min1[N],dic[N],tag[N],maxn,neg[N];
struct opt
{
    int type,l,r;
}opts[N];
map<int,int> m;
void pushdown(int id,int l,int r)
{
    if(tag[id])
    {
        tag[ls]=tag[rs]=tag[id];
        neg[ls]=neg[rs]=0;
        if(tag[id]-1>0) min0[ls]=min0[rs]=inf,min1[ls]=l,min1[rs]=mid+1;
        else min0[ls]=l,min0[rs]=mid+1,min1[ls]=min1[rs]=inf;
    }
    if(neg[id])
    {
        //if(tag[ls]||tag[rs]) throw ‘a‘;
        neg[ls]=!neg[ls],neg[rs]=!neg[rs];
        swap(min0[ls],min1[ls]);
        swap(min0[rs],min1[rs]);
    }
    neg[id]=tag[id]=0;
}
void update(int id)
{
    min0[id]=min(min0[ls],min0[rs]);
    min1[id]=min(min1[ls],min1[rs]);
}
void set(int id,int l,int r,int tl,int tr,int v)
{
    if(l>=tl&&r<=tr)
    {
        if(v) min0[id]=inf,min1[id]=l;
        else min0[id]=l,min1[id]=inf;
        tag[id]=v+1;
        neg[id]=0;
        return;
    }
    pushdown(id,l,r);
    if(tl<=mid) set(lc,v);
    if(tr>mid) set(rc,v);
    update(id);
}
void set2(int id,int l,int r,int tl,int tr)
{
    if(l>=tl&&r<=tr)
    {
        swap(min0[id],min1[id]);
        neg[id]=!neg[id];
        return;
    }
    pushdown(id,l,r);
    if(tl<=mid) set2(lc);
    if(tr>mid) set2(rc);
    update(id);
}
void build(int id,int l,int r)
{
    min0[id]=l;
    min1[id]=inf;
    if(l==r) return;
    build(ls,l,mid);
    build(rs,mid+1,r);
}
signed main()
{
    int n,cnt=0;
    //freopen("data.in","r",stdin);
    //freopen("my.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld%lld",&opts[i].type,&opts[i].l,&opts[i].r);
        if(!opts[i].l||!opts[i].r) throw "a";
        m[opts[i].l]=1;
        m[opts[i].r]=1;
        m[opts[i].r+1]=1;
    }   
    m[1]=1;
    for(map<int,int>::iterator it=m.begin();it!=m.end();it++)//通过map离散化
    {
        dic[++cnt]=(*it).first;
        (*it).second=cnt;
    }
    maxn=m.size();
    build(root);
    for(int i=1;i<=n;i++)
    {
        if(opts[i].type<=2) set(root,m[opts[i].l],m[opts[i].r],opts[i].type==1);
        else set2(root,m[opts[i].l],m[opts[i].r]);
        printf("%lld\n",dic[min0[1]]);
    }
}

 

Codeforces - 817F. MEX Queries

标签:www   节点   nbsp   离线   void   efi   stream   ||   open   

原文地址:https://www.cnblogs.com/linzhuohang/p/11330755.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!