题目描述
AKN觉得第一题太水了,不屑于写第一题,所以他又玩起了新的游戏。在游戏中,他发现,这个游戏的伤害计算有一个规律,规律如下
1、 拥有一个伤害串为长度为n的01串。
2、 给定一个范围[l,r],伤害为伤害串的这个范围内中1的个数
3、 会被随机修改伤害串中的数值,修改的方法是把[l,r]中的所有数xor上1
AKN想知道一些时刻的伤害,请你帮助他求出这个伤害
输入输出格式
输入格式:
第一行两个数n,m,表示长度为n的01串,有m个时刻
第二行一个长度为n的01串,为初始伤害串
第三行开始m行,每行三个数p,l,r
若p为0,则表示当前时刻改变[l,r]的伤害串,改变规则如上
若p为1,则表示当前时刻AKN想知道[l,r]的伤害
输出格式:
对于每次询问伤害,输出一个数值伤害,每次询问输出一行
输入输出样例
输入样例#1:
10 6 1011101001 0 2 4 1 1 5 0 3 7 1 1 10 0 1 4 1 2 6
输出样例#1:
3 6 1
说明
样例解释:
1011101001
1100101001
询问[1,5]输出3
1111010001
询问[1,10]输出6
0000010001
询问[2,6]输出1
数据范围:
10%数据2≤n,m≤10
另有30%数据2≤n,m≤2000
100%数据2≤n,m≤2*10^5
典型的线段树。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define SIGN(x) a[x].c
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 200010
using namespace std;
int n,m;
struct node{
int data,c;
int l,r;
}a[MAXN<<2];
void pushup(int rt){
DATA(rt)=DATA(LSON)+DATA(RSON);
}
void pushdown(int rt){
if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))
return;
SIGN(LSON)^=SIGN(rt);
DATA(LSON)=WIDTH(LSON)-DATA(LSON);
SIGN(RSON)^=SIGN(rt);
DATA(RSON)=WIDTH(RSON)-DATA(RSON);
SIGN(rt)=0;
}
void buildtree(int l,int r,int rt){
int mid;
LSIDE(rt)=l;
RSIDE(rt)=r;
if(l==r){
scanf("%1d",&DATA(rt));
return;
}
mid=l+r>>1;
buildtree(l,mid,LSON);
buildtree(mid+1,r,RSON);
pushup(rt);
}
void update(int l,int r,int rt){
int mid;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
SIGN(rt)^=1;
DATA(rt)=WIDTH(rt)-DATA(rt);
return;
}
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update(l,r,LSON);
if(mid<r)update(l,r,RSON);
pushup(rt);
}
long long query(int l,int r,int rt){
int mid;
long long ans=0;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
return DATA(rt);
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans+=query(l,r,LSON);
if(mid<r)ans+=query(l,r,RSON);
return ans;
}
int main(){
int f,x,y;
scanf("%d%d",&n,&m);
buildtree(1,n,1);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&f,&x,&y);
if(f==0)update(x,y,1);
if(f==1)printf("%lld\n",query(x,y,1));
}
return 0;
}