本题我在原网站通过了,详情看本篇题解最底下。
看到大家都用的 BIT,于是我补一个线段树题解。
解本题前先介绍两个关于异或的性质。
-
x ⊕ y ⊕ z = x ⊕ z ⊕ y x \oplus y \oplus z = x \oplus z \oplus y x⊕y⊕z=x⊕z⊕y。
-
x ⊕ 0 = x x \oplus 0 = x x⊕0=x。
对于操作 1 1 1,把 a x a_x ax 改为 a x ⊕ y a_x \oplus y ax⊕y,则 ∀ 1 ≤ i ≤ x , x ≤ j ≤ n \forall {1 \le i \le x,x \le j \le n} ∀1≤i≤x,x≤j≤n,有 ∑ k = i j a k \sum \limits _ {k = i} ^ {j} a_k k=i∑jak 改为 ( ∑ k = i j a k ) ⊕ y (\sum \limits _ {k = i} ^ {j} a_k) \oplus y (k=i∑jak)⊕y。
对于操作 2 2 2,输出 ∑ k = i j a k \sum \limits _ {k = i} ^ {j} a_k k=i∑jak 即可。
这是一个单点修改,区间查询的线段树。
下面给出代码,我写的动态开点线段树,虽然有 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 寄了,我只能去原题交代码,下面附上评测记录。记录。