原题链接:https://www.luogu.com.cn/problem/P2572

序列操作

题目描述

lxhgww 最近收到了一个 010101 序列,序列里面包含了 nnn 个数,下标从 000 开始。这些数要么是 000,要么是 111,现在对于这个序列有五种变换操作和询问操作:

0 l r 把 [l,r][l, r][l,r] 区间内的所有数全变成 000

1 l r 把 [l,r][l, r][l,r] 区间内的所有数全变成 111

2 l r 把 [l,r][l,r][l,r] 区间内的所有数全部取反,也就是说把所有的 000 变成 111,把所有的 111 变成 000

3 l r 询问 [l,r][l, r][l,r] 区间内总共有多少个 111

4 l r 询问 [l,r][l, r][l,r] 区间内最多有多少个连续的 111

对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?

输入格式

第一行两个正整数 n,mn,mn,m,表示序列长度与操作个数。
第二行包括 nnn 个数,表示序列的初始状态。
接下来 mmm 行,每行三个整数,表示一次操作。

输出格式

对于每一个询问操作,输出一行一个数,表示其对应的答案。

输入输出样例

输入 #1
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
输出 #1
5
2
6
5

说明/提示

【数据范围】
对于 30%30\%30% 的数据,1≤n,m≤10001\le n,m \le 10001≤n,m≤1000;
对于100%100\%100% 的数据,1≤n,m≤1051\le n,m \le 10^51≤n,m≤105 。

题解

上一题的升级版,因为区间取反操作的存在,我们必须同时记录000和111的包含左端点最长序列、包含右端点最长序列和整个区间最长序列,维护类似。又因为要求区间内111的数量,所以还要维护一个区间和。

相较于上一道题,本题多了区间取反标记。因为区间赋值时,之前的区间取反标记无意义;而区间取反时,区间赋值标记还会相应取反,所以在打标记的时候,区间取反标记一定是在区间赋值标记后传下来的,即在取反标记传入的时候赋值标记已经对应的改变了。所以在下传标记的时候,要先传取反标记,再传赋值标记(举例:区间赋000之后再区间取反相当于区间赋111,这时候虽然节点里有两个标记,但是区间取反标记已经没意义里,所以我们下传的时候需要先下传取反标记,再传赋值标记直接覆盖掉取反标记)。

其实还有一种更好理解的写法:打取反标记的时候不改变赋值标记,下传的时候直接按照原本的“先赋值,再取反”标记顺序下传。当然也可以在传取反标记的时候检查一下该节点有无赋值标记,有则修改赋值标记(相当于合并了赋值标记和取反标记),总之写法很多,自己能理解就好。

对照代码更好理解。

代码

第一种写法:

#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5;
struct node{int le,ri,llen[2],rlen[2],mlen[2],sum;bool clear,fill,rev;
}tree[M<<2];
int n,m,que[M];
void up(int v,int p)
{tree[v].llen[p]=(tree[ls].llen[p]==tree[ls].ri-tree[ls].le+1)?tree[ls].llen[p]+tree[rs].llen[p]:tree[ls].llen[p];tree[v].rlen[p]=(tree[rs].rlen[p]==tree[rs].ri-tree[rs].le+1)?tree[rs].rlen[p]+tree[ls].rlen[p]:tree[rs].rlen[p];tree[v].mlen[p]=max(tree[ls].rlen[p]+tree[rs].llen[p],max(tree[ls].mlen[p],tree[rs].mlen[p]));
}
void up(int v)
{up(v,0),up(v,1);tree[v].sum=tree[ls].sum+tree[rs].sum;
}
void push_fill(int v,int p)
{tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=tree[v].ri-tree[v].le+1;
}
void push_clear(int v,int p)
{tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=0;
}
void push_rev(int v)
{swap(tree[v].llen[0],tree[v].llen[1]);swap(tree[v].rlen[0],tree[v].rlen[1]);swap(tree[v].mlen[0],tree[v].mlen[1]);tree[v].sum=tree[v].ri-tree[v].le+1-tree[v].sum;tree[v].rev^=1;if(tree[v].fill||tree[v].clear)swap(tree[v].fill,tree[v].clear);
}
void down(int v)
{if(tree[v].rev){push_rev(ls),push_rev(rs);tree[v].rev=0;}if(tree[v].clear){push_clear(ls,1),push_fill(ls,0);push_clear(rs,1),push_fill(rs,0);tree[ls].clear=1,tree[ls].fill=tree[ls].rev=0;tree[rs].clear=1,tree[rs].fill=tree[rs].rev=0;tree[ls].sum=tree[rs].sum=0;tree[v].clear=0;}if(tree[v].fill){push_clear(ls,0),push_fill(ls,1);push_clear(rs,0),push_fill(rs,1);tree[ls].fill=1,tree[ls].clear=tree[ls].rev=0;tree[rs].fill=1,tree[rs].clear=tree[rs].rev=0;tree[ls].sum=tree[ls].ri-tree[ls].le+1;tree[rs].sum=tree[rs].ri-tree[rs].le+1;tree[v].fill=0;}
}
void build(int v,int le,int ri)
{tree[v].le=le,tree[v].ri=ri;if(le==ri){tree[v].llen[que[le]]=tree[v].rlen[que[le]]=tree[v].mlen[que[le]]=1;tree[v].sum=que[le];return;}int mid=le+ri>>1;build(ls,le,mid),build(rs,mid+1,ri);up(v);
}
void fill(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri){tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=0;tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=tree[v].ri-tree[v].le+1;tree[v].fill=1,tree[v].clear=tree[v].rev=0;return;}down(v);int mid=tree[v].le+tree[v].ri>>1;if(le<=mid)fill(ls,le,ri);if(mid<ri)fill(rs,le,ri);up(v);
}
void clear(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri){tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=0;tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=tree[v].ri-tree[v].le+1;tree[v].clear=1,tree[v].fill=tree[v].rev=0;return;}down(v);int mid=tree[v].le+tree[v].ri>>1;if(le<=mid)clear(ls,le,ri);if(mid<ri)clear(rs,le,ri);up(v);
}
void rev(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri){push_rev(v);return;}down(v);int mid=tree[v].le+tree[v].ri>>1;if(le<=mid)rev(ls,le,ri);if(mid<ri)rev(rs,le,ri);up(v);
}
int asksum(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].sum;down(v);int mid=tree[v].le+tree[v].ri>>1,r=0;if(le<=mid)r=asksum(ls,le,ri);if(mid<ri)r+=asksum(rs,le,ri);return r;
}
int asklen(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].mlen[1];down(v);int mid=tree[v].le+tree[v].ri>>1,r=min(tree[rs].le+tree[rs].llen[1]-1,ri)-max(tree[ls].ri-tree[ls].rlen[1]+1,le)+1;if(le<=mid)r=max(r,asklen(ls,le,ri));if(mid<ri)r=max(r,asklen(rs,le,ri));return r;
}
void in()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%d",&que[i]);
}
void ac()
{build(1,1,n);for(int i=1,op,a,b;i<=m;++i){scanf("%d%d%d",&op,&a,&b);++a,++b;if(!op)clear(1,a,b);else if(op==1)fill(1,a,b);else if(op==2)rev(1,a,b);else if(op==3)printf("%d\n",asksum(1,a,b));else printf("%d\n",asklen(1,a,b));}
}
int main()
{in(),ac();//system("pause");
}

第二种写法:

#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5;
struct node{int le,ri,llen[2],rlen[2],mlen[2],sum;bool clear,fill,rev;
}tree[M<<2];
int n,m,que[M];
void up(int v,int p)
{tree[v].llen[p]=(tree[ls].llen[p]==tree[ls].ri-tree[ls].le+1)?tree[ls].llen[p]+tree[rs].llen[p]:tree[ls].llen[p];tree[v].rlen[p]=(tree[rs].rlen[p]==tree[rs].ri-tree[rs].le+1)?tree[rs].rlen[p]+tree[ls].rlen[p]:tree[rs].rlen[p];tree[v].mlen[p]=max(tree[ls].rlen[p]+tree[rs].llen[p],max(tree[ls].mlen[p],tree[rs].mlen[p]));
}
void up(int v)
{up(v,0),up(v,1);tree[v].sum=tree[ls].sum+tree[rs].sum;
}
void push_fill(int v,int p)
{tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=tree[v].ri-tree[v].le+1;
}
void push_clear(int v,int p)
{tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=0;
}
void push_rev(int v)
{swap(tree[v].llen[0],tree[v].llen[1]);swap(tree[v].rlen[0],tree[v].rlen[1]);swap(tree[v].mlen[0],tree[v].mlen[1]);tree[v].sum=tree[v].ri-tree[v].le+1-tree[v].sum;tree[v].rev^=1;//if(tree[v].fill||tree[v].clear)swap(tree[v].fill,tree[v].clear);
}
void down(int v)
{if(tree[v].clear){push_clear(ls,1),push_fill(ls,0);push_clear(rs,1),push_fill(rs,0);tree[ls].clear=1,tree[ls].fill=tree[ls].rev=0;tree[rs].clear=1,tree[rs].fill=tree[rs].rev=0;tree[ls].sum=tree[rs].sum=0;tree[v].clear=0;}if(tree[v].fill){push_clear(ls,0),push_fill(ls,1);push_clear(rs,0),push_fill(rs,1);tree[ls].fill=1,tree[ls].clear=tree[ls].rev=0;tree[rs].fill=1,tree[rs].clear=tree[rs].rev=0;tree[ls].sum=tree[ls].ri-tree[ls].le+1;tree[rs].sum=tree[rs].ri-tree[rs].le+1;tree[v].fill=0;}if(tree[v].rev){push_rev(ls),push_rev(rs);tree[v].rev=0;}
}
void build(int v,int le,int ri)
{tree[v].le=le,tree[v].ri=ri;if(le==ri){tree[v].llen[que[le]]=tree[v].rlen[que[le]]=tree[v].mlen[que[le]]=1;tree[v].sum=que[le];return;}int mid=le+ri>>1;build(ls,le,mid),build(rs,mid+1,ri);up(v);
}
void fill(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri){tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=0;tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=tree[v].ri-tree[v].le+1;tree[v].fill=1,tree[v].clear=tree[v].rev=0;return;}down(v);int mid=tree[v].le+tree[v].ri>>1;if(le<=mid)fill(ls,le,ri);if(mid<ri)fill(rs,le,ri);up(v);
}
void clear(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri){tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=0;tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=tree[v].ri-tree[v].le+1;tree[v].clear=1,tree[v].fill=tree[v].rev=0;return;}down(v);int mid=tree[v].le+tree[v].ri>>1;if(le<=mid)clear(ls,le,ri);if(mid<ri)clear(rs,le,ri);up(v);
}
void rev(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri){push_rev(v);return;}down(v);int mid=tree[v].le+tree[v].ri>>1;if(le<=mid)rev(ls,le,ri);if(mid<ri)rev(rs,le,ri);up(v);
}
int asksum(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].sum;down(v);int mid=tree[v].le+tree[v].ri>>1,r=0;if(le<=mid)r=asksum(ls,le,ri);if(mid<ri)r+=asksum(rs,le,ri);return r;
}
int asklen(int v,int le,int ri)
{if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].mlen[1];down(v);int mid=tree[v].le+tree[v].ri>>1,r=min(tree[rs].le+tree[rs].llen[1]-1,ri)-max(tree[ls].ri-tree[ls].rlen[1]+1,le)+1;if(le<=mid)r=max(r,asklen(ls,le,ri));if(mid<ri)r=max(r,asklen(rs,le,ri));return r;
}
void in()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%d",&que[i]);
}
void ac()
{build(1,1,n);for(int i=1,op,a,b;i<=m;++i){scanf("%d%d%d",&op,&a,&b);++a,++b;if(!op)clear(1,a,b);else if(op==1)fill(1,a,b);else if(op==2)rev(1,a,b);else if(op==3)printf("%d\n",asksum(1,a,b));else printf("%d\n",asklen(1,a,b));}
}
int main()
{in(),ac();//system("pause");
}

Luogu2572 [SCOI2010]序列操作相关推荐

  1. P2572 [SCOI2010]序列操作

    对自己 & \(RNG\) : 骄兵必败 \(lpl\)加油! P2572 [SCOI2010]序列操作 题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要 ...

  2. BZOJ1858 [Scoi2010]序列操作 线段树

    欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1858 题意概括 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1 ...

  3. 【[SCOI2010]序列操作】

    好颓啊,我竟然来写了一道恶心的板子 旁边的魏佬嘲讽我,还用欺负我 嘤嘤嘤 那就不膜魏佬了 嘤嘤嘤 这是一道无聊的板子 看到这些操作,我们看到这些操作就知道我们需要维护的东西了 首先那个最长的连续的\( ...

  4. luogu P2572 [SCOI2010]序列操作

    传送门 这个题我写了差不多一周吧-- 终于改成了一个能在考试的时候写完的版本 大量的区间操作 1e5 显然线段树解决 确实是板子题 但是极其难调-- 最后听rabbithu学姐讲了一下才用" ...

  5. Luogu P2572 [SCOI2010]序列操作 线段树。。

    咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...

  6. bzoj 1858: [Scoi2010]序列操作

    2016-06-21 一看就是线段树,就是标记相互冲突,处理好,其余都是平常的. 1 #include<iostream> 2 #include<cstring> 3 #inc ...

  7. 【BZOJ-1858】序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 1961  Solved: 991 [Submit][Stat ...

  8. bzoj 2962 序列操作

    2962: 序列操作 Time Limit: 50 Sec  Memory Limit: 256 MB [Submit][Status][Discuss] Description 有一个长度为n的序列 ...

  9. 问题 F: 序列操作Ⅱ(前缀最大公约数,后缀最大公约数)

    问题 F: 序列操作Ⅱ 时间限制: 1 Sec 内存限制: 128 MB [提交][状态][讨论版] 题目描述 给定长度为 N 的正整数序列 A_1, A_2, A_3,-, A_N, 从中选择一个数 ...

  10. 问题 E: 序列操作Ⅰ(01背包)

    问题 E: 序列操作Ⅰ 时间限制: 1 Sec 内存限制: 128 MB [提交][状态][讨论版] 题目描述 给定长度为 N 的正整数序列 A_1, A_2, A_3,-, A_N, 从中选出若干个 ...

最新文章

  1. Linux 下ntpdate网络校时使用
  2. mysql 共享表空间_MySQL共享表空间概念
  3. 5.5 function
  4. SAP Spartacus list item点击之后的detail页面跳转
  5. ActiveMQ学习总结(5)——Java消息服务JMS详解
  6. php ajax练习
  7. opencv-api arcLength
  8. 牛客多校第五场 G subsequence 1 最长公共子序列/组合数
  9. 轻松搞定 Shell 玩转 HiveSQL
  10. 最短路径问题 图论
  11. Windows 7下硬盘安装Ubuntu 14.10图文教程【硬盘安装】
  12. Introduction to Computer Networking学习笔记(十五):End to End Delay 端对端延迟
  13. 解决Mac无法识别移动硬盘以及无法识别BootCamp Windows分区的问题
  14. 如何在论文后面插参考文献
  15. mono android 开机启动,浅析 Android 平台 mono执行机制 by郡墙
  16. C. Not Adjacent Matrix
  17. css模糊遮罩效果_遮罩效果 css3
  18. 微型计算机m3500q,爆发“小”宇宙 创新与实用完美结合 ——联想ThinkCentre M3500q超小商用台式机新品发布...
  19. 学学Gnuplot(常用命令及参数)
  20. 【计算机毕业设计】324企业人事信息管理系统设计与实现

热门文章

  1. tail -f 命令卡住
  2. 免责条款html5,蚂蚁HTML5社区
  3. SpringBoot中前后端数据交互
  4. cookie、session存储以及cookie使用环境 多数据存储批次加载渲染页面
  5. three.js 中的矩阵变换及两种旋转表达方式
  6. 2.3 利用FTP服务器下载和上传文件
  7. Oracle11g常用数据字典
  8. ZOJ 3432 Find the Lost Sock (水题)
  9. 【CC评网】2013.第44周 把握每天的第一个小时
  10. c# 代码编辑器 支持多种语言,支持多种编程语言与系统的跨平台代码编辑器——微软 Visual Studio Code...