P9631 [ICPC2020 Nanjing R] Just Another Game of Stones 题解
题目大意
给定
1 l r x 表示令所有
2 l r x 表示用石堆
(如果你还不了解 Nim 游戏,点这里)。
思路
我们知道,Nim 游戏中所有石堆的石子数异或和为
设当前异或和为
可以用吉司机线段树(Segment Tree Beats)维护操作一(取
(如果你还不了解吉司机线段树,点这里)。
AC 代码
#include<iostream>
#define mid ((l+r)>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
using namespace std;
const int N=200005;
struct node
{
int cnt[31],ccnt,p,op,sum,tag;
}tr[N<<2];
int a[N],n,m;
struct SegmentTreeBeats
{
void pushup(int rt)
{
if(tr[ls].p<tr[rs].p)
{
tr[rt].p=tr[ls].p;
tr[rt].ccnt=tr[ls].ccnt;
tr[rt].op=min(tr[ls].op,tr[rs].p);
tr[rt].sum=tr[ls].sum^tr[rs].sum;
for(int i=0;i<=30;i++)
tr[rt].cnt[i]=tr[ls].cnt[i]+tr[rs].cnt[i];
}
else if(tr[ls].p>tr[rs].p)
{
tr[rt].p=tr[rs].p;
tr[rt].ccnt=tr[rs].ccnt;
tr[rt].op=min(tr[rs].op,tr[ls].p);
tr[rt].sum=tr[rs].sum^tr[ls].sum;
for(int i=0;i<=30;i++)
tr[rt].cnt[i]=tr[ls].cnt[i]+tr[rs].cnt[i];
}
else
{
tr[rt].p=tr[ls].p;
tr[rt].ccnt=tr[ls].ccnt+tr[rs].ccnt;
tr[rt].op=min(tr[ls].op,tr[rs].op);
tr[rt].sum=tr[ls].sum^tr[rs].sum;
for(int i=0;i<=30;i++)
tr[rt].cnt[i]=tr[ls].cnt[i]+tr[rs].cnt[i];
}
}
void pushtag(int rt,int x)
{
if(tr[rt].p>=x)
return ;
if(tr[rt].ccnt&1)
tr[rt].sum^=tr[rt].p,tr[rt].sum^=x;
for(int i=0;i<=30;i++)
{
if(tr[rt].p>>i&1)
tr[rt].cnt[i]-=tr[rt].ccnt;
if(x>>i&1)
tr[rt].cnt[i]+=tr[rt].ccnt;
}
tr[rt].p=x;
tr[rt].tag=x;
}
void pushdown(int rt)
{
if(tr[rt].tag==-1)
return ;
pushtag(ls,tr[rt].tag);
pushtag(rs,tr[rt].tag);
tr[rt].tag=-1;
}
void build(int rt,int l,int r)
{
tr[rt].tag=-1;
if(l==r)
{
tr[rt].p=a[l];
tr[rt].sum=a[l];
tr[rt].ccnt=1;
tr[rt].op=1e18;
for(int i=0;i<=30;i++)
if(a[l]>>i&1)
tr[rt].cnt[i]++;
return ;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
void modify(int rt,int l,int r,int cl,int cr,int x)
{
if(tr[rt].p>=x)
return ;
if(l>=cl&&r<=cr&&tr[rt].op>x)
{
pushtag(rt,x);
return ;
}
pushdown(rt);
if(cl<=mid)
modify(ls,l,mid,cl,cr,x);
if(cr>mid)
modify(rs,mid+1,r,cl,cr,x);
pushup(rt);
}
int qsum(int rt,int l,int r,int cl,int cr)
{
if(l>=cl&&r<=cr)
return tr[rt].sum;
pushdown(rt);
int sum=0;
if(cl<=mid)
sum^=qsum(ls,l,mid,cl,cr);
if(cr>mid)
sum^=qsum(rs,mid+1,r,cl,cr);
return sum;
}
int qbit(int rt,int l,int r,int cl,int cr,int x)
{
if(l>=cl&&r<=cr)
return tr[rt].cnt[x];
pushdown(rt);
int sum=0;
if(cl<=mid)
sum+=qbit(ls,l,mid,cl,cr,x);
if(cr>mid)
sum+=qbit(rs,mid+1,r,cl,cr,x);
return sum;
}
}tree;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
tree.build(1,1,n);
while(m--)
{
int op,l,r,x;
cin>>op>>l>>r>>x;
if(op&1)
tree.modify(1,1,n,l,r,x);
else
{
int sum=tree.qsum(1,1,n,l,r),max=-1;
sum^=x;
for(int i=30;i>=0;i--)
{
if(sum>>i&1)
{
max=i;
break;
}
}
if(max==-1)
cout<<0<<endl;
else
cout<<tree.qbit(1,1,n,l,r,max)+(x>>max&1)<<endl;
}
}
return 0;
}