P5057 CQOI2006 简单题

题目描述

有一个 n 个元素的数组,每个元素初始均为 0。有 m 条指令,要么让其中一段连续序列数字反转——0 变 1,1
变 0(操作 1),要么询问某个元素的值(操作 2)。
例如当 n = 20 时,10 条指令如下:

输入格式

第一行包含两个整数 n, m,表示数组的长度和指令的条数; 以下 m 行,每行的第一个数 t 表示操作的种类:

若 t = 1,则接下来有两个数 L, R,表示区间 [L, R] 的每个数均反转; 若 t = 2,则接下来只有一个数 i,表示询问的下标。

输出格式

每个操作 2 输出一行(非 0 即 1),表示每次操作 2 的回答。

样例 #1

样例输入 #1

20 10
1 1 10
2 6
2 12
1 5 12
2 6
2 15
1 6 16
1 11 17
2 12
2 6

样例输出 #1

1
0
0
0
1
1

提示

对于 50% 的数据,1 ≤ n ≤ \(10^3\), 1 ≤ m ≤ \(10^4\)
对于 100% 的数据,1 ≤ n ≤ \(10^5\), 1 ≤ m ≤ 5 × \(10^5\),保证 L ≤ R。

分析

我们可以把区间翻转理解为区间加 \(1\),单点查询时只需要把答案与 \(2\) 取模即可。

#include<bits/stdc++.h>
using namespace std;
int a[1000005<<2],t[1000005<<2],ad[1000005<<2];
int n,m;
void pushup(int num){t[num]=t[num<<1]+t[num<<1|1];}
void pushdown(int num,int l,int r){
	int mid=l+r>>1;
	t[num<<1]+=ad[num]*(mid-l+1),t[num<<1|1]+=ad[num]*(r-mid);
	ad[num<<1]+=ad[num],ad[num<<1|1]+=ad[num];
	ad[num]=0;
}
void add(int l,int r,int num,int x,int y,int k){
	if(x>r||y<l)return;
	if(x<=l&&r<=y){
		t[num]+=k*(r-l+1);
		ad[num]+=k;
		return;
	}
	int mid=l+r>>1;
	pushdown(num,l,r);
	add(l,mid,num<<1,x,y,k),add(mid+1,r,num<<1|1,x,y,k);
	pushup(num);
}
int query(int l,int r,int num,int x){
	if(l==r)return t[num]&1;
	int mid=l+r>>1;
	pushdown(num,l,r);
	if(x<=mid)return query(l,mid,num<<1,x)&1;
	else return query(mid+1,r,num<<1|1,x)&1;
}
int main(){
	cin>>n>>m;
	for(int i=1,opt,x,y;i<=m;i++){
		cin>>opt;
		if(opt==1){
			cin>>x>>y;
			add(1,n,1,x,y,1);
		}else{
			cin>>x;
			cout<<query(1,n,1,x)<<endl;
		}
	}
	return 0;
}
posted @ 2023-06-24 14:13  alex_liu09  阅读(50)  评论(0)    收藏  举报