1. 程式人生 > >【CQOI 2006】簡單題

【CQOI 2006】簡單題

【題目】

題目背景:

CQOI 2006 T1

題目描述:

有一個 n 個元素的陣列,每個元素初始均為 0 。有 m 條指令,要麼讓其中一段連續序列數字反轉——0 變 1,1 變 0(操作1),要麼詢問某個元素的值(操作2)。例如當 n=20 時,10 條指令如下:

輸入格式:

輸入檔案第一行包含兩個整數 n,m,表示陣列的長度和指令的條數,以下 m 行,每行的第一個數 t 表示操作的種類。若 t=1,則接下來有兩個數 L, R (L ≤ R),表示區間 [L, R] 的每個數均反轉;若 t=2,則接下來只有一個數 I,表示詢問的下標。

輸出格式:

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

樣例資料:

輸入

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
0
0
0
1
1

備註:

【資料範圍】
50% 的資料滿足:1 ≤ n ≤ 1,000,1 ≤ m ≤ 10,000
100% 的資料滿足:1 ≤ n ≤ 100,000,1 ≤ m ≤ 500,000

【分析】

首先我們要知道,對於一個元素,如果將它反轉奇數次,那它就是 1,否則是 0

這樣的話我們就記錄一下每個元素的反轉次數,對區間 [ l , r ] 反轉就將區間 [ l , r ] 每個元素的反轉次數加一

詢問的時候,統計一下這個元素的反轉次數就行了

然後它就變成一道簡單的區間加問題,用線段樹就可以輕鬆解決

【程式碼】

可能是我們學校OJ的問題吧,cout 要比 printf 快些,不過這不是重點

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100005
using namespace std;
int tree[4*N];
void pushdown(int root)
{
	tree[root<<1]+=tree[root];
	tree[root<<1|1]+=tree[root];
	tree[root]=0;
}
void modify(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	{
		tree[root]++;
		return;
	}
	int mid=(l+r)>>1;
	if(tree[root])  pushdown(root);
	if(x<=mid)  modify(root<<1,l,mid,x,y);
	if(y>mid)  modify(root<<1|1,mid+1,r,x,y);
}
int find(int root,int l,int r,int x)
{
	if(l==r)
	  return tree[root];
	int ans,mid=(l+r)>>1;
	if(tree[root])  pushdown(root);
	if(x<=mid)  ans=find(root<<1,l,mid,x);
	else  ans=find(root<<1|1,mid+1,r,x);
	return ans;
}
int main()
{
	int n,m,i,s,x,y,ans;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;++i)
	{
		scanf("%d",&s);
		if(s==1)
		{
			scanf("%d%d",&x,&y);
			modify(1,1,n,x,y);
		}
		else
		{
			scanf("%d",&x);
			ans=find(1,1,n,x);
			if(ans&1)  cout<<'1'<<'\n';
			else  cout<<'0'<<'\n';
		}
	}
	return 0;
}