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;
}
相关推荐
此生决int4 分钟前
算法从入门到精通——前缀和
c++·算法·蓝桥杯
大大杰哥20 分钟前
leetcode hot100(4)矩阵
算法·leetcode·矩阵
小白|24 分钟前
cmake:昇腾CANN构建系统完全指南
java·c++·算法
nebula-AI25 分钟前
人工智能导论:模型与算法(未来发展与趋势)
人工智能·神经网络·算法·机器学习·量子计算·automl·类脑计算
炽烈小老头27 分钟前
【每天学习一点算法 2026/05/21】课程表
学习·算法
luoganttcc30 分钟前
大模型是否即将到达算法极限
算法
叶小鸡1 小时前
小鸡玩算法-力扣HOT100-动态规划(上)
算法·leetcode·动态规划
LuminousCPP1 小时前
数据结构 - 线性表第三篇:基于顺序表实现 C 语言通讯录(基础功能篇)
c语言·数据结构·经验分享·笔记·算法
_日拱一卒1 小时前
LeetCode:114二叉树展开为链表
java·开发语言·算法
无小道1 小时前
Redis——哈希类型相关指令
redis·算法·哈希算法