CF817F MEX Queries

一、题目

点此看题

二、解法

本题最关键的地方在于离散化,因为原来的数据范围达到了 1 e 18 1e18 1e18,但如果离散到 n n n 1 e 5 1e5 1e5级别的话就比较好做了。但是只离散 l , r l,r l,r是不够的,把 l + 1 , l − 1 , r + 1 , r − 1 l+1,l-1,r+1,r-1 l+1,l1,r+1,r1都离散一下是肯定不会错的(代码中只离散了 r + 1 r+1 r+1,这一部分不要参考),注意还要离散 1 1 1

离散化之后搞一个权值线段树维护 3 3 3种操作,搞一个覆盖标记和翻转标记,翻转的时候看有没有覆盖标记,没有的话才搞翻转标记。

#include 
#include 
using namespace std;
#define int long long
const int M = 100005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,op[M],l[M],r[M],q[3*M];
int sum[12*M],tag[12*M],rev[12*M];
void build(int i,int l,int r)
{
    sum[i]=rev[i]=0;tag[i]=-1;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
}
void up(int i)
{
    sum[i]=sum[i<<1]+sum[i<<1|1];
}
void down(int i,int l,int r)
{
    int mid=(l+r)>>1;
    if(tag[i]!=-1)
    {
        tag[i<<1]=tag[i];
        tag[i<<1|1]=tag[i];
        rev[i<<1]=0;rev[i<<1|1]=0;
        if(tag[i]==0)
            sum[i<<1]=sum[i<<1|1]=0;
        else
        {
            sum[i<<1]=mid-l+1;//nmsl cnm nmb wrnm
            sum[i<<1|1]=r-mid;
        }
        tag[i]=-1;
    }
    if(rev[i])
    {
        if(tag[i<<1]!=-1) tag[i<<1]^=1;
        else rev[i<<1]^=1;
        if(tag[i<<1|1]!=-1) tag[i<<1|1]^=1;
        else rev[i<<1|1]^=1;
        sum[i<<1]=mid-l+1-sum[i<<1];
        sum[i<<1|1]=r-mid-sum[i<<1|1];
        rev[i]=0;
    }
}
void upd(int i,int l,int r,int L,int R,int t)
{
    if(l>R || L>r) return ;
    if(L<=l && r<=R)
    {
        if(t==1)
        {
            tag[i]=1;
            rev[i]=0;
            sum[i]=r-l+1;
        }
        if(t==2)
        {
            tag[i]=0;
            rev[i]=0;
            sum[i]=0;
        }
        if(t==3)
        {
            if(tag[i]!=-1) tag[i]^=1;
            else rev[i]^=1;
            sum[i]=r-l+1-sum[i];
        }
        return ;
    }
    int mid=(l+r)>>1;
    down(i,l,r);
    upd(i<<1,l,mid,L,R,t);
    upd(i<<1|1,mid+1,r,L,R,t);
    up(i);
}
int ask(int i,int l,int r)
{
    if(l==r) return l;
    down(i,l,r);
    int mid=(l+r)>>1;
    if(sum[i<<1]<mid-l+1) return ask(i<<1,l,mid);
    return ask(i<<1|1,mid+1,r);
}
signed main()
{
    n=read();
    q[++m]=1;
    for(int i=1;i<=n;i++)
    {
        op[i]=read(),l[i]=read(),r[i]=read();
        q[++m]=l[i];q[++m]=r[i];q[++m]=r[i]+1;
    }
    sort(q+1,q+1+m);
    m=unique(q+1,q+1+m)-q-1;
    build(1,1,m);
    for(int i=1;i<=n;i++)
    {
        l[i]=lower_bound(q+1,q+1+m,l[i])-q;
        r[i]=lower_bound(q+1,q+1+m,r[i])-q;
        upd(1,1,m,l[i],r[i],op[i]);
        printf("%lld\n",q[ask(1,1,m)]);
    }
}

你可能感兴趣的:(线段树)