题解 P3870 【[TJOI2009]开关】
这个题我愣是交了好几遍没有过......
后来@_皎月半洒花dalao告诉我说要^儿子节点的tag,然后就明白了......
行吧,先上题面:
题目描述
现有N(2 ≤ N ≤ 100000)盏灯排成一排,从左到右依次编号为:1,2,......,N。然后依次执行M(1 ≤ M ≤ 100000)项操作,操作分为两种:第一种操作指定一个区间
[a, b],然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开),第二种操作是指定一个区间[a, b],要求你输出这个区间内有多少盏灯是打开的。灯在初始时都是关着的。输入输出格式
输入格式:
第一行有两个整数N和M,分别表示灯的数目和操作的数目。接下来有M行,每行有三个整数,依次为:c, a, b。其中c表示操作的种类,当c的值为0时,表示是第一种操作。当c的值为1时表示是第二种操作。a和b则分别表示了操作区间的左右边界(1 ≤ a ≤ b ≤ N)。
输出格式:
每当遇到第二种操作时,输出一行,包含一个整数:此时在查询的区间中打开的灯的数目。
这个题比较水有好处的一点是有很多题都和这个题基本一样。
然后我们看到这个题让我们统计一个线段内的某一种和和修改区间:
线段树啊!
然后我就把校门外的树的代码扒过来了......
评测记录
后果:听取WA声一片。
为啥呢?
因为儿子节点有可能比父亲节点提前改过了。
所以我们只能取反,把原先的状态反过来。
然后就成了提交记录
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=100001;
struct tree{
int l,r,flash,dark;
bool tag;
}segment[maxn<<2];
int n,m;
inline void update(int rt);
inline void pushdown(int rt);
inline void build_tree(int rt,int l,int r);
inline int query(int rt,int l,int r);
inline void modify(int rt,int l,int r);
int main()
{
cin>>n>>m;
build_tree(1,1,n);
while (m--)
{
char flag;
int l,r;
cin>>flag>>l>>r;
if (flag=='0')modify(1,l,r);
else cout<<query(1,l,r)<<'\n';
}
return 0;
}
inline void update(int rt)
{
int lson=rt<<1,rson=lson+1;
segment[rt].flash=segment[lson].flash+segment[rson].flash;
segment[rt].dark=segment[lson].dark+segment[rson].dark;
}
inline void pushdown(int rt)
{
int lson=rt<<1,rson=lson+1;
segment[lson].tag^=1;
segment[rson].tag^=1;
swap(segment[lson].dark,segment[lson].flash);
swap(segment[rson].dark,segment[rson].flash);
segment[rt].tag^=1;
}
inline void build_tree(int rt,int l,int r)
{
segment[rt].l=l,segment[rt].r=r;
if (l==r)
{
segment[rt].flash=0;
segment[rt].dark=1;
segment[rt].tag=false;
return;
}
int mid=(r+l)>>1,lson=rt<<1,rson=lson+1;
build_tree(lson,l,mid);
build_tree(rson,mid+1,r);
update(rt);
}
inline void modify(int rt,int l,int r)
{
if (segment[rt].l<=l&&segment[rt].r>=r)
{
if (segment[rt].l==l&&segment[rt].r==r)
{
segment[rt].tag^=1;
swap(segment[rt].flash,segment[rt].dark);
return;
}
if (segment[rt].tag)pushdown(rt);
int mid=(segment[rt].l+segment[rt].r)>>1,lson=rt<<1,rson=lson+1;
if (r<=mid)modify(lson,l,r);
else if (l>mid)modify(rson,l,r);
else
{
modify(lson,l,mid);
modify(rson,mid+1,r);
}
update(rt);
}
return ;
}
inline int query(int rt,int l,int r)
{
if (segment[rt].l<=l&&segment[rt].r>=r)
{
if (segment[rt].l==l&&segment[rt].r==r)
{
return segment[rt].flash;
}
if (segment[rt].tag)pushdown(rt);
int mid=(segment[rt].l+segment[rt].r)>>1,lson=rt<<1,rson=lson+1;
if (r<=mid)return query(lson,l,r);
else if (l>=mid+1)return query(rson,l,r);
else return query(lson,l,mid)+query(rson,mid+1,r);
}
return 0;
}
行吧......
题解 P3870 【[TJOI2009]开关】的更多相关文章
- 洛谷 P3870 [TJOI2009]开关 题解
原题链接 前置知识: 线段树的单点.区间的修改与查询. 一看,我们需要维护两个操作: 区间取反: 区间求和. (因为区间 \(1\) 的个数,就是区间的和) 典型的 线段树 . 如果你只会线段树的 区 ...
- 洛谷 P3870 [TJOI2009]开关
题意简述 有n盏灯,默认为关,有两个操作: 1.改变l~r的灯的状态(把开着的灯关上,关着的灯打开) 2.查询l~r开着的灯的数量 题解思路 维护一个线段树,支持区间修改,区间查询 懒标记每次^1 代 ...
- P3870 [TJOI2009]开关
思路 重题 代码 #include <iostream> #include <vector> #include <cstdio> #include <cstr ...
- 洛谷P3870 [TJOI2009]开关
题目描述 现有\(N(2 ≤ N ≤ 100000)\)盏灯排成一排,从左到右依次编号为:\(1,2,......,N\).然后依次执行\(M(1 ≤ M ≤ 100000)\)项操作,操作分为两种: ...
- 洛谷P3870 [TJOI2009] 开关 (线段树)
简单的省选题...... 打异或标记即可. 1 #include<bits/stdc++.h> 2 const int N=2e5+10; 3 using namespace std; 4 ...
- 题解 P3870 【[TJOI2009]开关】/基础分块学习小结
直接进入正题: 分块: 分块分块,就是把一个长串东西,分为许多块,这样,我们就可以在操作一个区间的时候,对于在区间里面完整的块,直接操作块,不完整的直接操作即可,因为不完整,再加上一个块本身就不大,复 ...
- 洛谷 3870 [TJOI2009]开关
[题解] 线段树基础题.对于每个修改操作把相应区间的sum改为区间长度-sum即可. #include<cstdio> #include<algorithm> #include ...
- [TJOI2009]开关 (线段树)
题目描述 现有N(2 ≤ N ≤ 100000)盏灯排成一排,从左到右依次编号为:1,2,......,N.然后依次执行M(1 ≤ M ≤ 100000)项操作,操作分为两种:第一种操作指定一个区间[ ...
- Luogu3870 [TJOI2009]开关 (分块)
线段树做法很简单,但分块好啊 #include <iostream> #include <cstdio> #include <cstring> #include & ...
随机推荐
- requests.get()解析
1.requests.get(url, params=None, headers=None, cookies=None, auth=None, timeout=None) Sends a GET re ...
- vue组件--通讯录
简介 在移动端开发中,通讯录是个很常见的需求. 通讯录通常要实现以下功能 首字母导航 滚动到一定位置首字母固定 在线通讯录demo 布局 通讯录是典型的上下两栏布局,上面是header,下面是内容区, ...
- SAO Utils – SAO风格启动菜单
SAO Utils 是一款拥有 SAO(刀剑神域)外观风格的启动器,搭载各种各样强大的小工具. 随时随地.在屏幕任何地方 按住鼠标左键和右键并向下拖动 即可呼出应用启动菜单(触控设备直接支持双指下滑手 ...
- 如何推行Code Review
这篇文章探讨的是如何在一个没有Code Review习惯的团队里面Code Review. 在进行Code Review的时候,审核人很多时候会对被审核人的代码指手画脚,在评价对方的代码,甚至是在批评 ...
- Hadoop源码编译环境搭建
准备工具: maven 3.0.0版本或者更高版本(配置中心库) protocbuff 2.5.0 http://www.zlib.net/ git bash(Windows环境可以用此工具执行编译命 ...
- ssm-maven 所需添加的所有映射
<dependencies> <!--Mybatis依赖--> <dependency> <groupId>org.mybatis</groupI ...
- UIWebView控件中 字体大小和字体样式的修改
修改UIWebView控件中字体的样式: NSString *htmlString = [NSString stringWithContentsOfFile:self.webPath encoding ...
- vi/vim命令详解
基础命令学习目录首页 原文链接:https://www.cnblogs.com/mondol/p/vi-examples.html 进入vi vi filename # 打开或新建文件,并将光标置于第 ...
- Vue 入门之数据绑定
什么是双向绑定? Vue 框架很核心的功能就是双向的数据绑定. 双向是指:HTML 标签数据 绑定到 Vue 对象,另外反方向数据也是绑定的.通俗点说就是,Vue 对象的改变会直接影响到 HTML 的 ...
- 第二阶段Sprint3
昨天:查看资料,开始视频录制部分的代码实现 今天:事实现保存到指定路径,并能够选择播放 遇到的问题:自动生成文件名,是否需要自己命名?怎么实现?