【线段树】开关(luogu 3870)

开关

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
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);//操作1
      	else printf("%d\n",find(1,x,y));
      }
}

你可能感兴趣的:(数据结构,线段树)