P3870 [TJOI2009] 开关[线段树(区间加 区间和 变种)]

P3870 [TJOI2009] 开关

时间限制: 1.00s 内存限制: 125.00MB

复制 Markdown

中文

退出 IDE 模式

题目描述

现有 n 盏灯排成一排,从左到右依次编号为:1,2,......,n。然后依次执行 m 项操作。

操作分为两种:

  1. 指定一个区间 [a,b],然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开);
  2. 指定一个区间 [a,b],要求你输出这个区间内有多少盏灯是打开的。

灯在初始时都是关着的。

输入格式

第一行有两个整数 n 和 m,分别表示灯的数目和操作的数目。

接下来有 m 行,每行有三个整数,依次为:c、a、b。其中 c 表示操作的种类。

  • 当 c 的值为 0 时,表示是第一种操作。
  • 当 c 的值为 1 时,表示是第二种操作。

a 和 b 则分别表示了操作区间的左右边界。

输出格式

每当遇到第二种操作时,输出一行,包含一个整数,表示此时在查询的区间中打开的灯的数目。

输入输出样例

输入 #1复制运行

复制代码
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4

输出 #1复制运行

复制代码
1
2

说明/提示

数据规模与约定

对于全部的测试点,保证 2≤n≤105,1≤m≤105,1≤a,b≤n,c∈{0,1}。

我们用二进制表示灯的开关 那么每次操作 就让所有的开关加1 然后对2取模 就可以模拟开关的过程 然后sum变为区间长度-sum 实现状态反转 这样就是一个最简单的变种

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
#define int long long
int a[N],n,m;
struct SegmentTree{
    int l,r;
    long long sum,add;
    #define l(x) tree[x].l
    #define r(x) tree[x].r
    #define sum(x) tree[x].sum
    #define add(x) tree[x].add
}tree[N<<2];
void pushdown(int p){
    if(add(p)){
        add(p<<1)+=add(p);add(p<<1)%=2;
        add(p<<1|1)+=add(p);add(p<<1|1)%=2;
        sum(p<<1)=r(p<<1)-l(p<<1)+1-sum(p<<1);
        sum(p<<1|1)=r(p<<1|1)-l(p<<1|1)+1-sum(p<<1|1);
    }
    add(p)=0;
}
void build(int p,int l,int r){
    l(p)=l,r(p)=r;
    if(l==r){sum(p)=a[l];return;}
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    sum(p)=sum(p<<1)+sum(p<<1|1);
}
void change(int p,int l,int r){
    if(l<=l(p)&&r>=r(p)){
        add(p)=(add(p)+1)%2;
        sum(p)=r(p)-l(p)+1-sum(p);
        return;
    }
    pushdown(p);
    int mid=(l(p)+r(p))>>1;
    if(l<=mid)change(p<<1,l,r);
    if(mid+1<=r)change(p<<1|1,l,r);
    sum(p)=sum(p<<1)+sum(p<<1|1);
}
int query(int p,int l,int r){
    if(l(p)>=l&&r(p)<=r)return sum(p);
    pushdown(p);
    int mid=(l(p)+r(p))>>1;
    int val=0;
    if(l<=mid){val=val+query(p<<1,l,r);}
    if(r>=mid+1){val=val+query(p<<1|1,l,r);}
    return val;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    build(1,1,n);
    while(m--){
        int op,l,r;
        cin>>op>>l>>r;
        if(op==0){
            change(1,l,r);
        }else cout<<query(1,l,r)<<'\n';
    }
    return 0;
}
相关推荐
嘴贱欠吻!2 小时前
Flutter鸿蒙开发指南(七):轮播图搜索框和导航栏
算法·flutter·图搜索算法
张祥6422889042 小时前
误差理论与测量平差基础笔记十
笔记·算法·机器学习
qq_192779873 小时前
C++模块化编程指南
开发语言·c++·算法
cici158745 小时前
大规模MIMO系统中Alamouti预编码的QPSK复用性能MATLAB仿真
算法·matlab·预编码算法
历程里程碑5 小时前
滑动窗口---- 无重复字符的最长子串
java·数据结构·c++·python·算法·leetcode·django
2501_940315266 小时前
航电oj:首字母变大写
开发语言·c++·算法
CodeByV6 小时前
【算法题】多源BFS
算法
TracyCoder1236 小时前
LeetCode Hot100(18/100)——160. 相交链表
算法·leetcode
浒畔居6 小时前
泛型编程与STL设计思想
开发语言·c++·算法
独处东汉7 小时前
freertos开发空气检测仪之输入子系统结构体设计
数据结构·人工智能·stm32·单片机·嵌入式硬件·算法