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;
}
相关推荐
Hcoco_me5 分钟前
大模型面试题49:从白话到进阶详解SFT 微调的 Loss 计算
人工智能·深度学习·神经网络·算法·机器学习·transformer·word2vec
修炼地6 分钟前
代码随想录算法训练营第五十三天 | 卡码网97. 小明逛公园(Floyd 算法)、卡码网127. 骑士的攻击(A * 算法)、最短路算法总结、图论总结
c++·算法·图论
小王和八蛋7 分钟前
负载均衡之DNS轮询
后端·算法·程序员
炽烈小老头13 分钟前
【每天学习一点算法 2026/01/07】Fizz Buzz
学习·算法
数据大魔方19 分钟前
【期货量化实战】威廉指标(WR)策略:精准捕捉超买超卖信号(Python源码)
开发语言·数据库·python·算法·github·程序员创富
why技术19 分钟前
可怕,看到一个冷血的算法。人心逐利,算法只会更聪明地逐利。
前端·后端·算法
有一个好名字30 分钟前
力扣-最大连续1的个数III
c++·算法·leetcode
橘颂TA36 分钟前
【剑斩OFFER】算法的暴力美学——力扣 43 题:字符串相乘
数据结构·算法·leetcode·职场和发展·哈希算法·结构与算法
海边的Kurisu36 分钟前
代码随想录算法第六十四天| To Be Continued
算法
less is more_093038 分钟前
文献学习——极端高温灾害下电缆型配电网韧性提升策略研究
笔记·学习·算法