Luogu P2572 序列操作
(是道线段树好题√)
题外话:这道题我也不知道卡了自己多少天,从初赛之前就开始做,一直到现在才a掉(时间跨度得有将近十天了吧?)
线段树,嗯,好像很简单的样子。
但事实上因为自己太菜了,卡了好久;
第一遍的思路简单的很,因为完全没有考虑标记下传的顺序问题,qf(取反)标记和chg(修改)标记各自下传各自的,于是乎就一直10分10分(没有好好写线段树Ⅱ的锅),咋改都不对,也没看出自己错在哪了;
然后被建议重构代码,于是尝试暴力出奇迹,\(O(nm)的暴力+O_2\)结果拿到了90pts??(jyy问号),特别迷惑;
Solution:
共有5个操作:(分别为
0 a b 把[a, b]区间内的所有数全变成0
1 a b 把[a, b]区间内的所有数全变成1
2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0
3 a b 询问[a, b]区间内总共有多少个1
4 a b 询问[a, b]区间内最多有多少个连续的1
要想完成这以上五个操作,在线段树上需要维护以下信息:
\(t[k].sum\) 记录k节点对应区间共有多少个1
\(t[k].L[0/1]\)分别记录k节点对应区间的左边有几个连续的0/1
\(t[k].R[0/1]\)分别记录k节点对应区间的右边有几个连续的0/1
↑维护左右连续0/1的个数,是因为在合并两个区间时,最长的连续的个数有可能来自左区间右侧和右区间左侧的合并
\(t[k].mx[0/1]\)记录k节点对应区间最长连续0/1的个数
两个标记:
\(t[k].qf\) 取反标记 0>不取反 1>取反
$t[k].chg $ 修改标记 -1>不修改 0> 修改为0 1==>修改为1
对于\(t[k].L[0/1],t[k].R[0/1],t[k].mx[0/1]\)的维护需要注意区间合并时可能会产生更长的连续段,要考虑并且维护,建树、修改、查询以及对应的重新维护区间的update此处省略…字,下面重点讲pushdown:
因为有两个不同的标记,在下传标记时要考虑先下传哪一个:
首先要明确是区间对于这棵线段树来说,取反标记和修改标记是无法通过modify函数的修改同时存在的(都pushdown掉了所以不会同时存在w)
啊,是凌乱的lz,我该怎么讲明白这个标记下传的问题
先讲下传规则再来感性李姐叭:
1.对于一个既有修改标记又有取反标记的节点,我们忽略取反标记,只下传修改标记
2.如果只有取反标记,又要分为两种情况:
- 要下传的子节点有修改标记,那么直接将修改标记取反,不下传取反标记;
- 要下传的子节点没有修改标记,将子节点的取反标记取反;
然后交换0/1的信息(swap大法好√)
最后不要忘记将当前节点的标记清空。
所以如果既有修改标记又有取反标记,那么取反标记一定是通过它的祖先节点下传的,而在下传时,修改标记的值就已经相应的被取反了,所以不需要再下传取反标记了w;
最后,是老Re lz的代码(是码风清奇的奇女子将就着看叭):
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int ans=0;
char last=' ',ch=getchar();
while(ch>'9'||ch<'0') last=ch,ch=getchar();
while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
if(last=='-') ans=-ans;
return ans;
}
const int mxn=200010;
int m,n,maxn;
int x[mxn];
struct node {
int sum;
int L[2],R[2];
int qf,chg;
int mx[2];
} t[mxn<<2];
void update(int k,int l,int r) {
t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
int mid=(l+r)>>1;
for(int i=0; i<=1; i++) {
t[k].L[i]=t[k<<1].L[i];
if(t[k<<1].L[i]==mid-l+1)
t[k].L[i]+=t[k<<1|1].L[i];
t[k].R[i]=t[k<<1|1].R[i];
if(t[k<<1|1].R[i]==r-mid)
t[k].R[i]+=t[k<<1].R[i];
t[k].mx[i]=max(t[k<<1].mx[i],max(t[k<<1|1].mx[i],t[k<<1].R[i]+t[k<<1|1].L[i]));
}
}
void build(int k,int l,int r) {
t[k].chg=-1;
t[k].qf=0;
if(l==r) {
t[k].L[0]=t[k].R[0]=t[k].mx[0]=x[l]==0;
t[k].L[1]=t[k].R[1]=t[k].mx[1]=x[l]==1;
if(x[l]) t[k].sum=1;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
update(k,l,r);
}
void pushdown(int k,int l,int r) {
int mid=(l+r)>>1;
if(t[k].chg!=-1) {
int p=t[k].chg;
t[k].qf=0;
t[k<<1].chg=t[k<<1|1].chg=p;
t[k<<1].qf=t[k<<1|1].qf=0;
t[k<<1].sum=(mid-l+1)*p;
t[k<<1|1].sum=(r-mid)*p;
t[k<<1].L[p]=t[k<<1].mx[p]=t[k<<1].R[p]=mid-l+1;
t[k<<1|1].L[p]=t[k<<1|1].mx[p]=t[k<<1|1].R[p]=r-mid;
t[k<<1].L[p^1]=t[k<<1].mx[p^1]=t[k<<1].R[p^1]=0;
t[k<<1|1].L[p^1]=t[k<<1|1].mx[p^1]=t[k<<1|1].R[p^1]=0;
t[k].chg=-1;
}
if(t[k].qf) {
t[k<<1].sum=mid-l+1-t[k<<1].sum;
t[k<<1|1].sum=r-mid-t[k<<1|1].sum;
if(t[k<<1].chg!=-1)
t[k<<1].chg^=1;
else
t[k<<1].qf^=1;
if(t[k<<1|1].chg!=-1)
t[k<<1|1].chg^=1;
else
t[k<<1|1].qf^=1;
swap(t[k<<1].L[0],t[k<<1].L[1]);
swap(t[k<<1].R[0],t[k<<1].R[1]);
swap(t[k<<1].mx[0],t[k<<1].mx[1]);
swap(t[k<<1|1].L[0],t[k<<1|1].L[1]);
swap(t[k<<1|1].R[0],t[k<<1|1].R[1]);
swap(t[k<<1|1].mx[0],t[k<<1|1].mx[1]);
t[k].qf=0;
}
}
void modify(int k,int l,int r,int x,int y,int q) {
pushdown(k,l,r);
if(x<=l&&r<=y) {
if(q==1||q==0) {
t[k].sum=(r-l+1)*q;
t[k].L[q]=t[k].R[q]=t[k].mx[q]=r-l+1;
t[k].L[q^1]=t[k].R[q^1]=t[k].mx[q^1]=0;
t[k].chg=q;
} else {
t[k].sum=(r-l+1)-t[k].sum;
t[k].qf^=1;
swap(t[k].L[0],t[k].L[1]);
swap(t[k].R[0],t[k].R[1]);
swap(t[k].mx[0],t[k].mx[1]);
}
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify(k<<1,l,mid,x,y,q);
if(y>mid) modify(k<<1|1,mid+1,r,x,y,q);
update(k,l,r);
}
int query(int k,int l,int r,int x,int y) {
pushdown(k,l,r);
if(x<=l&&r<=y)
return t[k].sum;
int mid=(l+r)>>1;
int rtn=0;
if(x<=mid) rtn+=query(k<<1,l,mid,x,y);
if(y>mid) rtn+=query(k<<1|1,mid+1,r,x,y);
return rtn;
}
int Query(int k,int l,int r,int x,int y) {
pushdown(k,l,r);
if(x<=l&&r<=y)
return t[k].mx[1];
int mid=(l+r)>>1;
int rtn=0;
if(x<=mid) rtn=max(rtn,Query(k<<1,l,mid,x,y));
if(y>mid) rtn=max(rtn,Query(k<<1|1,mid+1,r,x,y));
if(x<=mid&&y>mid)
rtn=max(rtn,min(mid-x+1,t[k<<1].R[1])+min(y-mid,t[k<<1|1].L[1]));
return rtn;
}
int main() {
n=read();
m=read();
for(int i=1; i<=n; i++)
x[i]=read();
build(1,1,n);
for(int i=1,op,a,b;i<=m;i++) {
op=read();
a=read();a++;
b=read();b++;
if(op==0)
modify(1,1,n,a,b,0);
if(op==1)
modify(1,1,n,a,b,1);
if(op==2)
modify(1,1,n,a,b,2);
if(op==3)
printf("%d\n",query(1,1,n,a,b));
if(op==4)
printf("%d\n",Query(1,1,n,a,b));
}
return 0;
}
Luogu P2572 序列操作的更多相关文章
- 【题解】Luogu P2572 [SCOI2010]序列操作
原题传送门:P2572 [SCOI2010]序列操作 这题好弱智啊 裸的珂朵莉树 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 操作1:把区间内所有数推平成0,珂朵莉树基本操作 ...
- P2572 [SCOI2010]序列操作
对自己 & \(RNG\) : 骄兵必败 \(lpl\)加油! P2572 [SCOI2010]序列操作 题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要 ...
- Python通用序列操作
1.序列概览 1.数据结构 序列.容器 Python中最基本的数据结构是序列,其有索引(从左到右第一个索引为0,从右到左第一个索引为-1). Python包含6中内建的序列: 列表 元组 字符串 Un ...
- 【BZOJ-2962】序列操作 线段树 + 区间卷积
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 678 Solved: 246[Submit][Status][Discuss] ...
- 【BZOJ-1858】序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1961 Solved: 991[Submit][Status ...
- bzoj 1858: [Scoi2010]序列操作
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MB 线段树,对于每个区间需要分别维护左右和中间的1和0连续个数,并在op=4时特殊 ...
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
- [bzoj]2962序列操作
[bzoj]2962序列操作 标签: 线段树 题目链接 题意 给你一串序列,要你维护三个操作: 1.区间加法 2.区间取相反数 3.区间内任意选k个数相乘的积 题解 第三个操作看起来一脸懵逼啊. 其实 ...
- bzoj 2962 序列操作
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description 有一个长度为n的序列, ...
随机推荐
- java支持断点续传文件上传和下载组件
java两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下: 实现思路: 1.服:利用ServerSocket搭建服务器,开启相应端口,进行长连接 ...
- 文件操作:fseek()
int fseek(FILE *stream, long offset, int fromwhere); fseek 用于二进制方式打开的文件,移动文件读写指针位置. int fseek( FIL ...
- HGOI20190814 省常中互测7
Problem A 中间值 对于$2$个非严格单增序列$\{A_n\} , \{B_n\}$,维护下列两个操作: 1 x y z: (x=0)时将$A_y = z$ , (x=1)时将$B_y = z ...
- Android 属性动画监听事件与一个菜单的例子
简单监听事件 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 3 ...
- <meta>标签 的一些用法
网上找到的一些资料:自己留着! 链接 :http://www.wzsky.net/html/Website/htmlcss/116165.html meta是html语言head区的一个辅助性标签.也 ...
- Eclipse常用快捷键与IDEA中的对比.
最近从github下载了一些项目,但是看了一下使用的编译器是IDEA的,所以就下载了一个IDEA. 这边可以提供几个网址:只要是针对各个下载idea之后的一些激活相关的帮助. http://idea. ...
- 3分割线左右间距(LinearLayoutManager.VERTICAL)
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=" ...
- git 指定自己的sshkey
在服务器上生成ssh-key以后,需要把公钥放在github上,但是,这个公钥只能放在一个账户里,如果放在第二个账户里,就会提示这个key已经被用了,这是前提 一个可能的场景是这样的: 你们公司有好几 ...
- MySort(选做)的实现
MySort(选做)的实现 题目内容 注意:研究sort的其他功能,要能改的动代码,需要答辩 模拟实现Linux下Sort -t : -k 2的功能. 要有伪代码,产品代码,测试代码(注意测试用例的设 ...
- python连redis测试
python 版本 3.x执行环境需要安装redis模块: pip install redis 执行脚本前,有redis-cli中查询key值: 执行脚本: ********************* ...