题解
先来讲一下我的做法
于是在考试的时候就爆0了。。。
但是O(logn)的insert太慢了,我们又考虑到题目只从尾端insert
于是我们就可以从下向上合并pushup
当它是父亲节点的右儿子是就可以把它的值上传了(因为这时它的父亲就有可能对答案做出贡献了)
如果是左儿子就停止上传
然后我们就愉快地发现这样做是均摊O(1)的
就过了。。。
这道题告诉我们:
1、在前驱值范围较小、运算有不具有结合律的时候是可以用线段树维护多个标记来解决的
2、尾端insert可以通过只在右儿子上传的信息的方法优化到均摊O(1)的
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 4000005
#define lc i<<1
#define rc i<<1|1
struct node{
int l,r;bool v[2],s[2];
}a[N<<2];
bool val[N];int num[N];
inline void pushup(int i)
{
a[i].v[1]=a[rc].v[a[lc].v[1]];
a[i].v[0]=a[rc].v[a[lc].v[0]];
a[i].s[1]=a[lc].s[1]^a[rc].s[a[lc].v[1]];
a[i].s[0]=a[lc].s[0]^a[rc].s[a[lc].v[0]];
}
void build(int i,int l,int r)
{
a[i].l=l;a[i].r=r;
if(l==r){num[l]=i;return;}
int mid=(l+r)>>1;
build(lc,l,mid);build(rc,mid+1,r);
}
int q,ans;
void query(int i,int l,int r)
{
if(a[i].l>r||a[i].r<l)return;
if(l<=a[i].l&&a[i].r<=r){
ans^=a[i].s[q];
q=a[i].v[q];
return;
}
query(lc,l,r);query(rc,l,r);
}
int main()
{
freopen("nand.in","r",stdin);
freopen("nand.out","w",stdout);
int n,m=0,i,op,l,r,x;
n=gi();build(1,1,n);
for(i=1;i<=n;i++){
op=gi();
if(op==1){
x=gi();
x^=ans;
val[++m]=x;
int tmp=num[m];
a[tmp].v[1]=a[tmp].s[1]=!(1&x);
a[tmp].v[0]=a[tmp].s[0]=1;
while((tmp>>1)&&(tmp&1)){
tmp>>=1;
pushup(tmp);
}
}
else{
l=gi();r=gi();
if(ans)l=m-l+1,r=m-r+1,swap(l,r);
ans=q=val[l];query(1,l+1,r);
printf("%d\n",ans);
}
}
}
还有,尽量节约内存开销。。。防止MLE
其实还有一种做法(by Master.Yi)
代码:
#include<bits/stdc++.h>
#define maxn 4000005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
//n: number of 0, len: total length.
int m,n,len,s[maxn],a[maxn],ans;
int main()
{
freopen("nand.in","r",stdin);
freopen("nand.out","w",stdout);
a[n=1]=0,a[n+1]=1e9;
read(m);int op,x,l,r,L,R;
while(m--){
read(op),read(x);
if(op==1){
x^=ans,len++;
if(x) s[n]=s[n-1]^((len-a[n])%4<=1);
else a[++n]=len,s[n]=s[n-1]^1,a[n+1]=1e9;
}
else{
l=x,read(r); if(ans) l=len-l+1,r=len-r+1,swap(l,r);
L=upper_bound(a+1,a+1+n,l)-a,R=upper_bound(a+1,a+1+n,r)-a-1;
if(a[L]>r&&a[R]<l) {printf("%d\n",ans=(r-l)%4<=1);continue;}
if(a[L]>r&&a[R]==l) {printf("%d\n",ans=(r-l+3)%4<=1);continue;}
ans=0;
if(L<R) ans=s[R-1]^s[L-1];
ans^=(a[L]-l-(a[L-1]==l)+3)%4<=1;
ans^=(r-a[R])%4<=1;
printf("%d\n",ans);
}
}
}