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

Posted wzc521

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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(n)sim Theta(n^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++

以上是关于[CSP-S模拟测试]:联(小清新线段树)的主要内容,如果未能解决你的问题,请参考以下文章

[CSP-S模拟测试]:树(树上LIS+主席树+线段树)

[CSP-S模拟测试]:F(DP+线段树)

[CSP-S模拟测试]:表格(动态开点二维线段树+离散化)

[CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)

csp-s模拟测试92

花神游历各国 题解(小清新线段树/树状数组+并查集)