luogu P6627 【[省选联考 2020 B 卷] 幸运数字】|标记永久化线段树

退役选手来写篇题解

把三种条件全部转化成区间修改

线段树离散化后维护一下

1.就相当与\([L,R]\)异或上 \(x\)

2.相当于一个区间\([A,A]\)异或上 \(x\)

3.相当于两个区间\([-1e9,B-1],[B+1,1e9]\)异或上 \(x\)

根据求答案的绝对值最小,绝对值相同取正数的原则

先把 \(0,1e9,-1e9\) 这些边界加入到离散化数组里

1.把 \(L-1,L,R-1,R\) 计入答案考虑

2.把 \(A-1,A,A+1\) 计入答案考虑

3.把 \(B-1,B,B-1\) 计入答案考虑

可以证明最优答案不会出现在这些点以外的地方


提供一个简要而且不那么严谨的证明

对于一个异或值相同的区间\([L,R]\)

如果答案为此异或值,那么答案只会有三种情况

\(L\) \((0<L<R)\)

\(0\) \((L<0<R)\)

\(R\) \((L<R<0)\)

根据我们的区间转化原则,有可能存在

对于一个异或值相同的是多个区间\([L1,R1][L2,R2]..\)

那也可以把他们认为成独立的多个区间,答案一定也是里面的子集


细节问题可以看代码

本人退役选手,菜的一批

我省选写这题的时候就是数组开小了,应该开\(4n\)长度的线段树

所以这题我考的时候只有35分

很多东西是个人理解,要是说错了什么地方,望告知

#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
#define lb lower_bound
#define pb push_back
inline int read(){
	int x=0,f=1; char c=getchar();
	while(c<'0'||c>'9'){ if(c=='-')f=-1; c=getchar(); }
	while('0'<=c&&c<='9'){ x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
const int N=1e6+10;
struct Seg{
	int l,r,sum;
	#define l(x) tree[x].l
	#define r(x) tree[x].r
	#define sum(x) tree[x].sum
}tree[N<<2];
#define ls p<<1
#define rs p<<1|1
#define mid ((l(p)+r(p))>>1)
void build(int p,int l,int r){
	l(p)=l,r(p)=r;
	if(l(p)==r(p))return;
	build(ls,l,mid);
	build(rs,mid+1,r);
}
void update(int p,int l,int r,int d){
	if(l<=l(p)&&r(p)<=r){ sum(p)^=d; return; }
	if(l<=mid)update(ls,l,r,d);
	if(r>mid)update(rs,l,r,d);
}
int ans[N<<2];
void query(int p,int d){
	d^=sum(p);
	if(l(p)==r(p)){ ans[l(p)]=d; return; }
	query(ls,d),query(rs,d);
}
int b[N<<2],len;
struct node{
	int t,l,r,w,x;
}e[N];
vector<int>sxr;
signed main(){
	int n=read();
	b[++len]=-1e9; b[++len]=0; b[++len]=1e9;
	for(int i=1,t,l,r,w,x;i<=n;i++){
		t=read();
		if(t==1){
			l=read(),r=read(),w=read();
			b[++len]=l,b[++len]=r;
			b[++len]=l-1,b[++len]=r+1;
		}else{
			x=read(),w=read();
			b[++len]=x;
			b[++len]=x-1;
			b[++len]=x+1;
		}
		e[i]=(node){t,l,r,w,x};
	}
	sort(b+1,b+1+len);
	len=unique(b+1,b+1+len)-b-1;
	build(1,1,len);
	for(int i=1,t,l,r,w,x;i<=n;i++){
		t=e[i].t;
		if(t==1){
			l=e[i].l,r=e[i].r,w=e[i].w;
			l=lb(b+1,b+1+len,l)-b;
			r=lb(b+1,b+1+len,r)-b;
			update(1,l,r,w);
		}else if(t==2){
			x=e[i].x,w=e[i].w;
			x=lb(b+1,b+1+len,x)-b;
			update(1,x,x,w);
		}else if(t==3){
			x=e[i].x,w=e[i].w;
			x=lb(b+1,b+1+len,x)-b;
			if(x>1)update(1,1,x-1,w);
			if(x<len)update(1,x+1,len,w);
		}
	}
	query(1,0);
	int Ans=0;
	for(int i=1;i<=len;i++)
	if(ans[i]>Ans){
		Ans=ans[i];
		sxr.clear();
		sxr.pb(b[i]);
	}else if(ans[i]==Ans)sxr.pb(b[i]);
	printf("%lld ",Ans);
	Ans = -(1ll<<62);
	for(int i=0;i<sxr.size();i++){
		if(abs(sxr[i])<abs(Ans))Ans=sxr[i];
		else if(abs(sxr[i])==abs(Ans))Ans=max(Ans,sxr[i]);
	}
	printf("%lld\n",Ans);
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/13198638.html
今日推荐