题目描述
YYX家门前的街上有N(2<=N<=100000)盏路灯,在晚上六点之前,这些路灯全是关着的,六点之后,会有M(2<=m<=100000)个人陆续按下开关,这些开关可以改变从第i盏灯到第j盏灯的状态,现在YYX想知道,从第x盏灯到第y盏灯中有多少是亮着的(1<=i,j,x,y<=N)
输入描述
第 1 行: 用空格隔开的两个整数N和M
第 2..M+1 行: 每行表示一个操作, 有三个用空格分开的整数: 指令号(0代表按下开关,1代表询问状态), x 和 y
输出描述
第 1..询问总次数行:对于每一次询问,输出询问的结果
样例输入
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
样例输出
1
2
数据范围及提示
一共4盏灯,5个操作,下面是每次操作的状态(X代表关上的,O代表开着的):
XXXX -> OOXX -> OXOO -> 询问1~3 -> OOXX -> 询问1~4
题解:线段树模板题
#include <cstdio>
struct TREE{
int l,r,sum;
bool lazy;
}tree[400005];
int n,m,x,y,z;
using namespace std;
inline int read()
{
int f=1,x=0;
char ch=getchar();
if (ch=='-')
{
f=-1;
ch=getchar();
}
while ((ch<'0')||(ch>'9')) ch=getchar();
while ((ch>='0')&&(ch<='9'))
{
x=x*10+ch-48;
ch=getchar();
}
return f*x;
}
inline void build(int root,int l,int r)
{
tree[root].l=l;tree[root].r=r;
if (l==r) return;
build(root*2,l,(l+r)/2);
build(root*2+1,(l+r)/2+1,r);
}
inline void push_down(int root,int l,int r)
{
if (!tree[root].lazy) return;
int mid=(l+r)/2;
tree[root*2].sum=(mid-l+1)-tree[root*2].sum;
tree[root*2].lazy=!tree[root*2].lazy;
tree[root*2+1].sum=(r-mid)-tree[root*2+1].sum;
tree[root*2+1].lazy=!tree[root*2+1].lazy;
tree[root].lazy=0;
}
inline void change(int root,int l,int r)
{
int ll=tree[root].l,rr=tree[root].r;
int mid=(ll+rr)/2;
if ((l<=ll)&&(rr<=r))
{
tree[root].sum=(rr-ll+1)-tree[root].sum;
tree[root].lazy=!tree[root].lazy;
return;
}
push_down(root,ll,rr);
if (l<=mid) change(root*2,l,r);
if (r>mid) change(root*2+1,l,r);
tree[root].sum=tree[root*2].sum+tree[root*2+1].sum;
}
inline int find(int root,int l,int r)
{
int ll=tree[root].l,rr=tree[root].r,s=0;
int mid=(ll+rr)/2;
if ((l<=ll)&&(rr<=r)) return tree[root].sum;
push_down(root,ll,rr);
if (l<=mid) s+=find(root*2,l,r);
if (r>mid) s+=find(root*2+1,l,r);
return s;
}
int main()
{
n=read(),m=read();
build(1,1,n);
for (int i=1;i<=m;i++)
{
x=read(),y=read(),z=read();
if (x==0) change(1,y,z); else
printf("%d\n",find(1,y,z));
}
return 0;
}