开关
luogu 3870
题目大意:
有n个灯,每一次会按一个区间中的所有灯(开变关,关变开,操作0),或询问某个区间中有多少个灯是亮着的(操作2),按操作进行,输出
输入样例#1:
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
输出样例#1:
1
2
解题思路:
用线段树,然后开关灯就是每次加1再模2,如果整个区间的话就直接用区间长度减去已亮灯数
代码:
#include<cstdio>
using namespace std;
int n,m,u,x,y;
struct rec
{int l,r,num,lazy;
}tree[400500];
void make(int dep)//建树
{if (tree[dep].l==tree[dep].r) return;int mid=(tree[dep].l+tree[dep].r)>>1;tree[dep*2].l=tree[dep].l,tree[dep*2].r=mid;tree[dep*2+1].l=mid+1,tree[dep*2+1].r=tree[dep].r;make(dep*2);make(dep*2+1);return;
}
void pass(int dep)//向下传递
{if (tree[dep].lazy){tree[dep*2].lazy^=1;//取反tree[dep*2+1].lazy^=1;tree[dep*2].num=tree[dep*2].r-tree[dep*2].l+1-tree[dep*2].num;//取反tree[dep*2+1].num=tree[dep*2+1].r-tree[dep*2+1].l+1-tree[dep*2+1].num;tree[dep].lazy=0;}
}
void change(int dep,int l,int r)
{if (tree[dep].l==l&&tree[dep].r==r)//到了{tree[dep].num=tree[dep].r-tree[dep].l+1-tree[dep].num;//取反tree[dep].lazy^=1;return;}if (tree[dep].l>=tree[dep].r) return;pass(dep);int mid=(tree[dep].l+tree[dep].r)>>1;if (r<=mid)//全在左边{change(dep*2,l,r);tree[dep].num=tree[dep*2].num+tree[dep*2+1].num;return;}if (l>mid){change(dep*2+1,l,r);tree[dep].num=tree[dep*2].num+tree[dep*2+1].num;return;}change(dep*2,l,mid);change(dep*2+1,mid+1,r);tree[dep].num=tree[dep*2].num+tree[dep*2+1].num;return;
}
int find(int dep,int l,int r)//查询
{if (tree[dep].l==l&&tree[dep].r==r) return tree[dep].num;if (tree[dep].l>=tree[dep].r) return 0;pass(dep);int mid=(tree[dep].l+tree[dep].r)>>1;if (r<=mid) return find(dep*2,l,r);if (l>mid) return find(dep*2+1,l,r);return find(dep*2,l,mid)+find(dep*2+1,mid+1,r);
}
int main()
{scanf("%d %d",&n,&m);tree[1].l=1;tree[1].r=n;make(1);for (int i=1;i<=m;++i){scanf("%d %d %d",&u,&x,&y);if (!u) change(1,x,y);//操作1else printf("%d\n",find(1,x,y));}
}