[线段树]Easy问题(重庆2006省选)
Description
有一个n个元素的数组,每个元素初始均为0。有m条指令,要么让其中一段连续序列数字反转--0变1,1变0(操作1),要么询问某个元素的值(操作2)。 例如当n=20时,10条指令如下:
操作 回答 操作后的数组
1 1 10 N/A 11111111110000000000
2 6 1 11111111110000000000
2 12 0 11111111110000000000
1 5 12 N/A 11110000001100000000
2 6 0 11110000001100000000
2 15 0 11110000001100000000
1 6 16 N/A 11110111110011110000
1 11 17 N/A 11110111111100001000
2 12 1 11110111111100001000
2 6 1 11110111111100001000
Input
输入第一行包含两个整数n,m,表示数组的长度和指令的条数。以下m行,每行的第一个数t表示操作的种类。若t=1,则接下来有两个数L,R(L<=R),表示区间[L,R]的每个数均反转;若t=2,则接下来只有一个数I,表示询问的下标。
Output
输出中有多行.每个操作2输出一行(非0即1),表示每个操作2的回答。
Sample Input
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
Sample Output
1 0 0 0 1 1
HINT
50%的数据满足:1<=n<=1000, 1<=m<=10000。 100%的数据满足:1<=n<=100000, 1<=m<=500000。
=========================以上题目========================
#include <cstdio> // 4 5|6 7 // 1 2 3 4 5|6 7 8 9 10 // 1 2 3 4 5|6 7 8 9 // 3 4 5 6|7 8 9 // 3 4 5 6|7 8 9 10 // 1|2 int n,m,l[1000001],r[1000001],t[1000001],res = 0; //t[i]表示编号为i的线段有几次取反操作。 void su(int x,int ll,int rr){ t[x] = 0;l[x] = ll;r[x] = rr; if(ll == rr){return;} int len = (rr - ll) / 2; su(x * 2,ll,ll + len); su(x * 2 + 1,ll + len + 1,rr); } void f(int x,int a,int b){ if(l[x] == a && r[x] == b){ t[x]++; return; } int mid = (l[x] + r[x]) / 2; if(a > mid){ f(x * 2 + 1,a,b); } else if(b <= mid){ f(x * 2,a,b); } else{ f(x * 2,a,mid); f(x * 2 + 1,mid + 1,b); } } void ask(int x,int a){ res += t[x]; if(l[x] == r[x]) return; int mid = (l[x] + r[x]) / 2; if(a <= mid){ ask(x * 2,a); } else{ ask(x * 2 + 1,a); } } int main() { scanf("%d %d",&n,&m); su(1,1,n); for(int i = 1;i <= m;i++){ int x,a,b; scanf("%d",&x); if(x == 1){ scanf("%d %d",&a,&b); f(1,a,b); } else{ scanf("%d",&a); res = 0; ask(1,a); printf("%d\n",res % 2); } } return 0; }