NKOI 3732 wjj的01序列

来源:互联网 发布:西门子编程线 编辑:程序博客网 时间:2024/06/10 19:57
P3732wjj 的零一序列时间限制 : - MS   空间限制 : 265536 KB 评测说明 : 时限1000ms
问题描述

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

提示


#include<cstdio>#include<iostream>#include<cstring>#define LL long longusing 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;}}}



0 0