[ABC185F] Range Xor Query 题解

该篇文章详细讲解了如何使用C++中的线段树数据结构,通过异或操作处理区间修改问题,适合IT竞赛和算法学习者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本题我在原网站通过了,详情看本篇题解最底下。

看到大家都用的 BIT,于是我补一个线段树题解。

解本题前先介绍两个关于异或的性质。

  • x ⊕ y ⊕ z = x ⊕ z ⊕ y x \oplus y \oplus z = x \oplus z \oplus y xyz=xzy

  • x ⊕ 0 = x x \oplus 0 = x x0=x

对于操作 1 1 1,把 a x a_x ax 改为 a x ⊕ y a_x \oplus y axy,则 ∀ 1 ≤ i ≤ x , x ≤ j ≤ n \forall {1 \le i \le x,x \le j \le n} 1ix,xjn,有 ∑ k = i j a k \sum \limits _ {k = i} ^ {j} a_k k=ijak 改为 ( ∑ k = i j a k ) ⊕ y (\sum \limits _ {k = i} ^ {j} a_k) \oplus y (k=ijak)y

对于操作 2 2 2,输出 ∑ k = i j a k \sum \limits _ {k = i} ^ {j} a_k k=ijak 即可。

这是一个单点修改,区间查询的线段树。

下面给出代码,我写的动态开点线段树,虽然有 90 90 90 行,但是快读快写占了许多行,如果看不懂可以跳过,其作用与标准输入输出相同。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls l,mid
#define rs mid+1,r
#define Getchar() p1==p2 and (p2=(p1=Inf)+fread(Inf,1,1<<21,stdin),p1==p2)?EOF:*p1++
#define Putchar(c) p3==p4 and (fwrite(Ouf,1,1<<21,stdout),p3=Ouf),*p3++=c
char Inf[1<<21],Ouf[1<<21],*p1,*p2,*p3=Ouf,*p4=Ouf+(1<<21);
inline void read(int &x,char c=Getchar())
{
	bool f=c!='-';
	x=0;
	while(c<48 or c>57) c=Getchar(),f&=c!='-';
	while(c>=48 and c<=57) x=(x<<3)+(x<<1)+(c^48),c=Getchar();
	x=f?x:-x;
}
inline void write(int x)
{
	if(x<0) Putchar('-'),x=-x;
	if(x>=10) write(x/10),x%=10;
	Putchar(x^48);
}
int n,q,t,x,y,cnt;
struct node
{
	int sum,lazy;
	node *lc,*rc;
	inline void pushup()
	{
		sum=lc->sum^rc->sum;
	}
	inline void pushdown()
	{
		if(lazy)
		{
			lc->lazy^=lazy,rc->lazy^=lazy,lc->sum^=lazy,rc->sum^=lazy;
			lazy=0;
		}
	}
};
node tree[600010],*root;
inline node *newnode()
{
	return &tree[++cnt];
}
inline node *build(int l,int r)
{
	node *rt=newnode();
	if(l==r) read(rt->sum);
	if(l<r)
	{
		int mid=(l+r)/2;
		rt->lc=build(ls),rt->rc=build(rs),rt->pushup();
	}
	return rt;
}
inline void fix(node *rt,int l,int r,const int &p,const int &val)
{
	if(l==r)
	{
		rt->sum^=val,rt->lazy^=val;
		return;
	}
	rt->pushdown();
	int mid=(l+r)/2;
	if(p<=mid) fix(rt->lc,ls,p,val);
	else fix(rt->rc,rs,p,val);
	rt->pushup();
}
inline int ask(node *rt,int l,int r,const int &L,const int &R)
{
	if(L<=l && r<=R) return rt->sum;
	rt->pushdown();
	int mid=(l+r)/2,ret=0;
	if(L<=mid) ret^=ask(rt->lc,ls,L,R);
	if(R>mid) ret^=ask(rt->rc,rs,L,R);
	return ret;
}
signed main()
{
	read(n),read(q),root=build(1,n);
	for(int i=1,op,x,y;i<=q;i++)
	{
		read(op),read(x),read(y);
		if(op==1) fix(root,1,n,x,y);
		else write(ask(root,1,n,x,y)),Putchar('\n');
	}
	fwrite(Ouf,1,p3-Ouf,stdout),fflush(stdout);
	return 0;
}

由于洛谷的 RMJ 寄了,我只能去原题交代码,下面附上评测记录。记录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值