分析
这道题用可持久化权值线段树做,记录存在的最左边的数,最右边的数,对于连续的一段区间是可以打表找到答案的,如果不连续按照题目求,对于重复的区间,需要打标记,表示已经计算过了,就不需要再计算了
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1e7+5;
int lazy[N],lef[N],rig[N],ls[N],rs[N],cnt,rt; long long w[N];
inline signed iut(){
rr int 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;
}
void print(long long ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed calc(int x){
return x&1?((x&3)==1?3:1):(x<<1)+(x&3);
}
inline void update(int &rt,int l,int r,int x,int y){
if (lazy[rt]) return;
if (!rt) rt=++cnt;
if (l==x&&r==y){
lef[rt]=x,rig[rt]=y,lazy[rt]=1;
w[rt]=calc(y-1)^calc(x-1); return;
}
rr int mid=(l+r)>>1;
if (y<=mid) update(ls[rt],l,mid,x,y);
else if (x>mid) update(rs[rt],mid+1,r,x,y);
else update(ls[rt],l,mid,x,mid),update(rs[rt],mid+1,r,mid+1,y);
if (lef[ls[rt]]) lef[rt]=lef[ls[rt]]; else lef[rt]=lef[rs[rt]];
if (rig[rs[rt]]) rig[rt]=rig[rs[rt]]; else rig[rt]=rig[ls[rt]];
w[rt]=w[ls[rt]]^w[rs[rt]];
if (lef[rs[rt]]&&rig[ls[rt]]) w[rt]^=1ll*(lef[rs[rt]]+rig[ls[rt]])*(lef[rs[rt]]-rig[ls[rt]]);
if (lazy[ls[rt]]&&lazy[rs[rt]]) lazy[rt]=1;
}
signed main(){
for (rr int t=iut();t;--t){
rr int q=iut(),x,y;
if (q&1) x=iut(),y=iut(),update(rt,1,1e9,x,y);
else print(w[1]),putchar(10);
}
return 0;
}