• [CSP-S模拟测试]:联(小清新线段树)


    题目描述

    由于出题人懒所以没有背景。
    一个无限长的$01$序列,初始全为$0$,每次选择一个区间$[l,r]$进行操作,有三种操作:
    $ullet 1 l r$将$[l,r]$中所有元素变成$1$。
    $ullet 2 l r$将$[l,r]$中所有元素变成$0$。
    $ullet 3 l r$将$[l,r]$中所有元素异或上$1$。
    每次操作后询问最左边的$0$在哪个位置。


    输入格式

    第一行一个数$m$,表示序列长度和操作数量。
    接下来$m$行,每行三个数$ty l r$,描述一次操作。


    输出格式

    输出共$m$行,第$i$行输出一个数表示第$i$次操作后的答案。


    样例

    样例输入:

    3
    1 3 4
    3 1 6
    2 1 3

    样例输出:

    1
    3
    1


    数据范围与提示

    令$n$为$max(r)$。
    对于测试点$1sim 4$:$n,mleqslant 10^3$。
    对于测试点$5sim 6$:只有$1$操作。
    对于测试点$7sim 10$:只有$1,2$操作。
    对于测试点$11sim 15$:$nleqslant 10^5$。
    对于测试点$16sim 20$:无特殊限制。
    对于所有的数据,$nleqslant 10^{18},mleqslant 10^5$。


    题解

    看数据范围,肯定是要离散化的,但是离散化的时候需要注意还要将$l+1$和$r+1$离散。

    对于只有操作$1,2$的情况,我们可以用线段树直接维护。

    那么考虑情况$3$我们可以怎么处理。

    如果一段区间都是一样的,我们可以直接将其翻转,然后$return$。

    不过这样做可以被很轻松的卡掉,比方说序列是$0101010......$,每次都执行操作$3$,那么会被卡成$n^2$。

    但是对于这到柯朵莉树都能$A$掉的题,这就无关紧要了。

    时间复杂度:$Theta(m)sim Theta(m^2)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    #define L(x) x<<1
    #define R(x) x<<1|1
    #define inf 0x3f3f3f3f
    using namespace std;
    map<long long,long long> mp;
    struct rec{int ty;long long l,r;}e[200001];
    int m;
    int n;
    long long pre[5000000];
    long long trsam[10000000],trans[10000000],lz[10000000];
    void pushup(int x)
    {
    	trans[x]=min(trans[L(x)],trans[R(x)]);
    	trsam[x]=(trsam[L(x)]==trsam[R(x)])?trsam[L(x)]:-1;
    }
    void pushdown(int x,int l,int r)
    {
    	if(lz[x]==-1)return;
    	int mid=(l+r)>>1;
    	lz[L(x)]=lz[R(x)]=trsam[L(x)]=trsam[R(x)]=lz[x];
    	if(!trsam[L(x)])trans[L(x)]=l;
    	else trans[L(x)]=inf;
    	if(!trsam[R(x)])trans[R(x)]=mid+1;
    	else trans[R(x)]=inf;
    	lz[x]=-1;
    }
    void build(int x,int l,int r)
    {
    	trans[x]=inf;
    	lz[x]=-1;
    	if(l==r)
    	{
    		trans[x]=l;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(L(x),l,mid);
    	build(R(x),mid+1,r);
    	pushup(x);
    }
    void change(int x,int l,int r,int L,int R,int opt)
    {
    	if(R<l||r<L)return;
    	if(L<=l&&r<=R&&trsam[x]!=-1)
    	{
    		switch(opt)
    		{
    			case 1:trsam[x]=1;lz[x]=1;break;
    			case 2:trsam[x]=0;lz[x]=0;break;
    			case 3:trsam[x]^=1;lz[x]=trsam[x];break;
    		}
    		if(!trsam[x])trans[x]=l;
    		else trans[x]=inf;
    		return;
    	}
    	int mid=(l+r)>>1;
    	pushdown(x,l,r);
    	change(L(x),l,mid,L,R,opt);
    	change(R(x),mid+1,r,L,R,opt);
    	pushup(x);
    }
    int main()
    {
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)
    		scanf("%d%lld%lld",&e[i].ty,&e[i].l,&e[i].r);
    	for(int i=1;i<=m;++i)
    	{
    		pre[i*4-3]=e[i].l, pre[i*4-2]=e[i].r;
    		pre[i*4-1]=e[i].l+1, pre[i*4]=e[i].r+1;
    	}
    	pre[m*4+1]=1;
    	sort(pre+1,pre+m*4+2);
    	n=unique(pre+1,pre+m*4+2)-pre-1;
    	for(int i=1;i<=m;++i)
    	{
    		mp[lower_bound(pre+1,pre+n+1,e[i].r+1)-pre]=e[i].r+1;
    		mp[lower_bound(pre+1,pre+n+1,e[i].l+1)-pre]=e[i].l+1;
    		long long now=e[i].l;
    		e[i].l=lower_bound(pre+1,pre+n+1,e[i].l)-pre;
    		mp[e[i].l]=now;
    		now=e[i].r;
    		e[i].r=lower_bound(pre+1,pre+n+1,e[i].r)-pre;
    		mp[e[i].r]=now;
    	}
    	mp[1]=1;
    	build(1,1,n);
    	for(int i=1;i<=m;++i)
    	{
    		change(1,1,n,e[i].l,e[i].r,e[i].ty);
    		printf("%lld
    ",mp[trans[1]]);
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    面试题63 二叉搜索树的第k个结点
    面试题62 序列化二叉树
    面试题61 把二叉树打印成多行
    面试题60 按之字形顺序打印二叉树
    centos下Nginx代理访问web服务
    回文数
    两数之和--哈希表unordered_map
    删除链表的倒数第N个节点---链表的应用
    基础篇,排序(冒泡排序,快速排序)
    linuxC网络聊天室简单代码,CSDN博客迁移
  • 原文地址:https://www.cnblogs.com/wzc521/p/11615873.html
Copyright © 2020-2023  润新知