P3732wjj 的零一序列 | ||
|
问题描述
wjj 在 nodgd 的序列店里买了一个长度为n的0,1序列{a1,a2,…,an},想拿来做数学题。
定义f(l,r)为序列第l位到序列第r位的数字异或和。有三种操作:
• 0 L R 询问有多少个l,r满足L≤l≤r≤R,使得f(l,r)=0。
• 1 L R 询问有多少个l,r满足L≤l≤r≤R,使得f(l,r)=1。
• 2 x 将位置x的数取反。
其中 1≤L≤R≤n, 1≤x≤n。 你需要给出对序列进行q次上述的操作的结果。
输入格式
第一行包含一个正整数n,表示序列的长度。
第二行包含n个整数,表示序列中的数,数字只会为0或1。
第三行包含一个正整数q,表示操作的数量。
接下来q行,每行一种操作,格式如题目所述。
输出格式
输出多行,其中对于每一种询问操作输出一行,包含一个非负整数,表示相应的答案。
样例输入
10
1 0 0 1 0 0 1 0 1 1
4
0 1 3
1 2 5
2 3
1 2 5
样例输出
3
6
4
提示
#include<cstdio>
#include<iostream>
#include<cstring>
#define LL long long
using namespace std;
const int maxn=100005;
int sum[maxn],tot,a,n,b,t,d,ans;
struct wk{int a,b,left,right,v,lazy;}tree[maxn<<2];
inline void _read(int &x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
void buildtree(int x,int y){
int r=++tot;
tree[r].a=x,tree[r].b=y;
if(x<y){
int mid=(x+y)>>1;
tree[r].left=tot+1;
buildtree(x,mid);
tree[r].right=tot+1;
buildtree(mid+1,y);
tree[r].v=tree[tree[r].left].v+tree[tree[r].right].v;
}
else tree[r].v=sum[x];
}
void down(int r){
int ls=tree[r].left,rs=tree[r].right,mid=(tree[r].a+tree[r].b)>>1;
tree[ls].lazy^=tree[r].lazy;
tree[rs].lazy^=tree[r].lazy;
tree[ls].v=mid-tree[r].a+1-tree[ls].v;
tree[rs].v=tree[r].b-mid-tree[rs].v;
tree[r].lazy=0;
}
void add(int r){
if(tree[r].a>b||tree[r].b<a)return;
if(tree[r].lazy)down(r);
if(tree[r].a>=a&&tree[r].b<=b){
tree[r].lazy^=1;
tree[r].v=tree[r].b-tree[r].a+1-tree[r].v;
return;
}
int ls=tree[r].left,rs=tree[r].right,mid=(tree[r].a+tree[r].b)>>1;
if(a<=mid)add(ls);
if(b>mid)add(rs);
tree[r].v=tree[ls].v+tree[rs].v;
}
int ask(int r){
if(tree[r].lazy)down(r);
int mid=(tree[r].a+tree[r].b)>>1;
int ls=tree[r].left,rs=tree[r].right;
if(tree[r].a>=a&&tree[r].b<=b)return tree[r].v;
int temp=0;
if(a<=mid)temp+=ask(ls);
if(b>mid)temp+=ask(rs);
return temp;
}
LL getans(int t){
int cnt1=ask(1);
int cnt0=b-a+1-cnt1;
if(t==0){
LL ans=0;
if(cnt1>1)ans+=(LL)(cnt1-1)*cnt1/2;
if(cnt0>1)ans+=(LL)(cnt0-1)*cnt0/2;
return ans;
}
return (LL)cnt1*cnt0;
}
int main(){
int q,x;
_read(n);
for(int i=1;i<=n;i++){
_read(x);
sum[i]=sum[i-1]^x;
}
buildtree(0,n);
_read(q);
while(q--){
_read(t);
if(t==2) {
_read(d);
a=d,b=n;
add(1);
}
else{
_read(a);_read(b);
a--;
cout<<getans(t)<<endl;
}
}
}