#线段树,离散#nssl 1476 联


分析

由于下标过大,考虑离散,不仅仅是区间左右端点
假设只有一个区间从1到\(x\),那么修改后答案应该是\(x+1\)
所以说还要记录右端点+1的位置,你以为这就能A了吗
为了避免标记被覆盖,无论是否找到区间,都要下传标记,并且如果当前标记为异或,
那么在修改完之后原来的标记异或抵消,全0变全1,全1变全0,查询就类似权值线段树的方法就好了
时间复杂度\(O(nlog_2n)\)


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
typedef long long lll;
const int N=300011;
int lazy[N<<2],z[N],m,n;
lll w[N<<2],b[N],l[N],r[N];
inline lll iut(){
	rr lll ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(lll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void doit(int k,int l,int r,int z){
	if (!z) return;
	if (z==1) w[k]=r-l+1;
		else if (z==2) w[k]=0;
		    else w[k]=r-l+1-w[k];
	if (z==3) lazy[k]^=z;
	    else lazy[k]=z;
}
inline void pdown(int k,int l,int r){
	if (!lazy[k]||l==r) return; 
	rr int mid=(l+r)>>1;
	doit(k<<1,l,mid,lazy[k]);
	doit(k<<1|1,mid+1,r,lazy[k]);
	lazy[k]=0;
}
inline void update(int k,int l,int r,int x,int y,int z){
	pdown(k,l,r);
	if (l==x&&r==y){doit(k,l,r,z); return;}
	rr int mid=(l+r)>>1;
	if (y<=mid) update(k<<1,l,mid,x,y,z);
	else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
	    else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
	w[k]=w[k<<1]+w[k<<1|1];
}
inline signed query(int k,int l,int r){
	if (l==r) return l;
	rr int mid=(l+r)>>1; pdown(k,l,r);
	if (w[k<<1]==mid-l+1) return query(k<<1|1,mid+1,r);
	    else return query(k<<1,l,mid);
}
signed main(){
	m=iut(),b[n=1]=1;
	for (rr int i=1;i<=m;++i){
		z[i]=iut(),l[i]=iut(),r[i]=iut();
	    b[++n]=l[i],b[++n]=r[i],b[++n]=r[i]+1;
	}
	sort(b+1,b+1+n),n=unique(b+1,b+1+n)-b-1;
	for (rr int i=1;i<=m;++i){
		l[i]=lower_bound(b+1,b+1+n,l[i])-b;
		r[i]=lower_bound(b+1,b+1+n,r[i])-b;
		update(1,1,n,l[i],r[i],z[i]);
		print(b[query(1,1,n)]),putchar(10); 
	}
	return 0;
} 
posted @ 2020-08-14 20:44  lemondinosaur  阅读(105)  评论(0编辑  收藏  举报