1. 程式人生 > >【TJOI 2009】開關

【TJOI 2009】開關

【題目】

傳送門

題目描述:

現有 n n 2 2 n n

100000 100000 )盞燈排成一排,從左到右依次編號為: 1 1 2 2
,…, n n 。然後依次執行 m m 1 1
m m 100000 100000 )項操作,操作分為兩種:第一種操作指定一個區間 [ a , b a, b ] ,然後改變編號在這個區間內的燈的狀態(把開著的燈關上,關著的燈開啟),第二種操作是指定一個區間 [ a , b a, b ] ,要求你輸出這個區間內有多少盞燈是開啟的。燈在初始時都是關著的。

輸入格式:

第一行有兩個整數 n n m m ,分別表示燈的數目和操作的數目。
接下來有 m m 行,每行有三個整數,依次為: c , a , b c, a, b 。其中 c c 表示操作的種類,當 c c 的值為 0 0 時,表示是第一種操作。當 c c 的值為 1 1 時表示是第二種操作。 a a b b 則分別表示了操作區間的左右邊界( 1 1 a a b b n n )。

輸出格式:

每當遇到第二種操作時,輸出一行,包含一個整數:此時在查詢的區間中開啟的燈的數目。

樣例資料:

輸入
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4

輸出
1
2


【分析】

題解:線段樹

假設 0 0 表示關著的燈, 1 1 表示開著的燈

我們用兩個陣列 s u m x , 0 sum_{x,0} 表示 x x 0 0 的個數, s u m x , 1 sum_{x,1} 表示 x x 1 1 的個數

然後只用累計取反操作的次數(累加或異或都可以),若要取反,則交換 s u m x , 0 sum_{x,0} s u m x , 1 sum_{x,1} 即可

剩下的就是基礎的線段樹操作了

【程式碼】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
int sum[N<<2][2],mark[N<<2];
void build(int root,int l,int r)
{
	if(l==r)
	{
		sum[root][0]=1;
		return;
	}
	int mid=(l+r)>>1;
	build(root<<1,l,mid);
	build(root<<1|1,mid+1,r);
	sum[root][0]=sum[root<<1][0]+sum[root<<1|1][0];
}
void pushdown(int root)
{
	swap(sum[root<<1][0],sum[root<<1][1]);
	swap(sum[root<<1|1][0],sum[root<<1|1][1]);
	mark[root<<1]^=1,mark[root<<1|1]^=1,mark[root]=0;
}
void modify(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	{
		mark[root]^=1;
		swap(sum[root][0],sum[root][1]);
		return;
	}
	int mid=(l+r)>>1;
	if(mark[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);
	sum[root][0]=sum[root<<1][0]+sum[root<<1|1][0];
	sum[root][1]=sum[root<<1][1]+sum[root<<1|1][1];
}
int query(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	  return sum[root][1];
	int ans=0,mid=(l+r)>>1;
	if(mark[root])  pushdown(root);
	if(x<=mid)  ans+=query(root<<1,l,mid,x,y);
	if(y>mid)  ans+=query(root<<1|1,mid+1,r,x,y);
	return ans;
}
int main()
{
	int n,m,i,s,x,y;
	scanf("%d%d",&n,&m);
	build(1,1,n);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d",&s,&x,&y);
		if(s==0)  modify(1,1,n,x,y);
		if(s==1)  printf("%d\n",query(1,1,n,x,y));
	}
	return 0;
}