BZOJ 1230 [Usaco2008 Nov]lites 开关灯:线段树异或

时间:2021-07-09 16:18:42

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1230

题意:

  有n盏灯,一开始全是关着的。

  有m次操作(p,a,b)。p为0,则将区间[a,b]内的所有灯反转;p为1,则输出[a,b]中有多少盏灯是亮的。

题解:

  线段树区间异或。

  与一般线段树有两点不同:

    (1)更新lazy时为:lazy ^= 1

    (2)更新dat时为:dat = len - dat

AC Code:

 #include <iostream>
#include <stdio.h>
#include <string.h>
#define MAX_N 500005
#define INF 10000000 using namespace std; int n,m;
int tot;
int dat[MAX_N];
int lazy[MAX_N];
int lson[MAX_N];
int rson[MAX_N]; void init_segment()
{
tot=;
memset(dat,,sizeof(dat));
memset(lazy,,sizeof(lazy));
memset(lson,-,sizeof(lson));
memset(rson,-,sizeof(rson));
} void create_kid(int now)
{
if(lson[now]==-) lson[now]=tot++;
if(rson[now]==-) rson[now]=tot++;
} void push_down(int now,int len)
{
if(lazy[now])
{
dat[lson[now]]=len-(len>>)-dat[lson[now]];
dat[rson[now]]=(len>>)-dat[rson[now]];
lazy[lson[now]]^=lazy[now];
lazy[rson[now]]^=lazy[now];
lazy[now]=;
}
} void push_up(int now)
{
dat[now]=dat[lson[now]]+dat[rson[now]];
} void update(int a,int b,int k,int l,int r,int x)
{
if(a<=l && r<=b)
{
dat[k]=r-l+-dat[k];
lazy[k]^=x;
return;
}
if(r<a || b<l) return;
create_kid(k);
push_down(k,r-l+);
int mid=(l+r)>>;
update(a,b,lson[k],l,mid,x);
update(a,b,rson[k],mid+,r,x);
push_up(k);
} void query(int a,int b,int k,int l,int r,int &sum)
{
if(a<=l && r<=b)
{
sum+=dat[k];
return;
}
if(r<a || b<l) return;
create_kid(k);
push_down(k,r-l+);
int mid=(l+r)>>;
query(a,b,lson[k],l,mid,sum);
query(a,b,rson[k],mid+,r,sum);
} int main()
{
init_segment();
scanf("%d%d",&n,&m);
int p,a,b;
for(int i=;i<m;i++)
{
scanf("%d%d%d",&p,&a,&b);
if(p==) update(a,b,,,n,);
else
{
int sum=;
query(a,b,,,n,sum);
printf("%d\n",sum);
}
}
}