欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1858


题意概括

  lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: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,对于每一种询问操作,lxhgww都需要给出回答


题解

  是一题暴力的线段树!

  总共除了1的总个数之外,还要维护6个量,分别是(当前区间内)从左开始连续的0的个数,从又开始连续的0的个数,区间内最长的连续的0的个数;同理,1也有3个。这题多打几个子程序是缩减代码量的好方法,这样便于查找错误。这题真的拼仔细!


代码

#include <cstring>
#include <cstdio>
int n,m,ra[101000],op,a,b;
int max2(int a,int b){return a>b?a:b;}
int max3(int a,int b,int c){return max2(max2(a,b),c);}
struct Segtree{int tot,add,t100,t101,t110,t000,t001,t010,le,ri,si;void set(int l,int r){tot=t100=t101=t110=t000=t001=t010=0;add=-1,le=l,ri=r,si=ri-le+1;}
}t[101000*4];
void swap(int &a,int &b){int c=a;a=b,b=c;
}
void pushup(int rt){int ls=rt*2,rs=rt*2+1;t[rt].tot=t[ls].tot+t[rs].tot;t[rt].t110=t[ls].t110;if (t[ls].t110==t[ls].si)t[rt].t110+=t[rs].t110;t[rt].t101=t[rs].t101;if (t[rs].t101==t[rs].si)t[rt].t101+=t[ls].t101;t[rt].t100=max3(t[ls].t101+t[rs].t110,t[ls].t100,t[rs].t100);t[rt].t010=t[ls].t010;if (t[ls].t010==t[ls].si)t[rt].t010+=t[rs].t010;t[rt].t001=t[rs].t001;if (t[rs].t001==t[rs].si)t[rt].t001+=t[ls].t001;t[rt].t000=max3(t[ls].t001+t[rs].t010,t[ls].t000,t[rs].t000);
}
void build(int rt,int le,int ri){t[rt].add=-1,t[rt].le=le,t[rt].ri=ri,t[rt].si=ri-le+1;if (le==ri){t[rt].tot=t[rt].t101=t[rt].t110=ra[le];t[rt].t001=t[rt].t010=!ra[le];return;}int mid=(le+ri)/2,ls=rt*2,rs=rt*2+1;build(ls,le,mid);build(rs,mid+1,ri);pushup(rt);
}
void pushnew(int rt,int op){if (op<2)t[rt].add=op;else if (t[rt].add==-1)t[rt].add=2;else if (t[rt].add==2)t[rt].add=-1;elset[rt].add=!t[rt].add;if (op==0)t[rt].tot=t[rt].t100=t[rt].t101=t[rt].t110=0,t[rt].t000=t[rt].t010=t[rt].t001=t[rt].si;else if (op==1)t[rt].tot=t[rt].t100=t[rt].t101=t[rt].t110=t[rt].si,t[rt].t000=t[rt].t010=t[rt].t001=0;else if (op==2){t[rt].tot=t[rt].si-t[rt].tot;swap(t[rt].t000,t[rt].t100);swap(t[rt].t010,t[rt].t110);swap(t[rt].t001,t[rt].t101);}
}
void pushdown(int rt){if (t[rt].add!=-1){pushnew(rt*2,t[rt].add);pushnew(rt*2+1,t[rt].add);t[rt].add=-1;}
}
void update(int rt,int le,int ri,int xle,int xri,int op){if (le>xri||ri<xle)return;if (xle<=le&&ri<=xri){pushnew(rt,op);return;}pushdown(rt);int mid=(le+ri)/2;update(rt*2,le,mid,xle,xri,op);update(rt*2+1,mid+1,ri,xle,xri,op);pushup(rt);
}
int querytot(int rt,int le,int ri,int xle,int xri){if (le>xri||ri<xle)return 0;if (xle<=le&&ri<=xri)return t[rt].tot;pushdown(rt);int mid=(le+ri)/2;return querytot(rt*2,le,mid,xle,xri)+querytot(rt*2+1,mid+1,ri,xle,xri);
}
Segtree query(int rt,int le,int ri,int xle,int xri){Segtree ans;ans.set(le,ri);if (le>xri||ri<xle)return ans;if (xle<=le&&ri<=xri)return t[rt];pushdown(rt);int mid=(le+ri)/2;Segtree ls=query(rt*2,le,mid,xle,xri),rs=query(rt*2+1,mid+1,ri,xle,xri);ans.t110=ls.t110;if (ls.t110==ls.si)ans.t110+=rs.t110;ans.t101=rs.t101;if (rs.t101==rs.si)ans.t101+=ls.t101;ans.t100=max3(ls.t101+rs.t110,ls.t100,rs.t100);ans.t010=ls.t010;if (ls.t010==ls.si)ans.t010+=rs.t010;ans.t001=rs.t001;if (rs.t001==rs.si)ans.t001+=ls.t001;ans.t000=max3(ls.t001+rs.t010,ls.t000,rs.t000);return ans;
}
int queryans(int a,int b){Segtree tt=query(1,1,n,a,b);return max3(tt.t100,tt.t101,tt.t110);
}
int main(){scanf("%d%d",&n,&m);for (int i=1;i<=n;i++)scanf("%d",&ra[i]);build(1,1,n);for (int i=1;i<=m;i++){scanf("%d%d%d",&op,&a,&b);a++,b++;if (op<3)update(1,1,n,a,b,op);else if (op==3)printf("%d\n",querytot(1,1,n,a,b));else if (op==4){printf("%d\n",queryans(a,b));}}    return 0;
}

  

转载于:https://www.cnblogs.com/zhouzhendong/p/BZOJ1858.html

BZOJ1858 [Scoi2010]序列操作 线段树相关推荐

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

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

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

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

  3. bzoj 2962 序列操作 线段树

    这个题卡常数.. 首先c比较小,所以可以考虑dp转移,对于合并子序列就直接枚举跨区间的就可以了 对于反转操作,要注意只有奇数位置才会变成相反数 对于增加操作,可以考虑抽象成组合数学问题: 对于(a1+ ...

  4. P2572 [SCOI2010]序列操作

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

  5. 【codevs2421】【BZOJ1858】序列操作,线段树

    传送门1 传送门2 写在前面:垃圾题目毁我青春 思路: 这是一道很明显但你就是要调很久而且不会舒服的线段树 每个区间你需要维护7个量和2个标记 分别是1的总数,最长连续1(0)长度,左(右)端点的连续 ...

  6. Wannafly挑战赛22 D 整数序列 (线段树维护三角函数值)

    链接:https://ac.nowcoder.com/acm/contest/160/D 来源:牛客网 整数序列 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语 ...

  7. luogu P2572 [SCOI2010]序列操作

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

  8. 2020-2021年度第二届全国大学生算法设计与编程挑战赛 (春季赛)- 天才的操作(线段树+主席树+树上倍增)

    题目链接:点击查看 题目分析:刚看到这个题目的时候,口胡了一个假算法,觉得对于每次询问的操作 [l,r][l,r][l,r] ,只需要找到指令集区间 [l,r][l,r][l,r] 内覆盖到点 kkk ...

  9. BZOJ_1798__Codevs_2216_[AHOI_2009]_行星序列_(线段树)

    描述 BZOJ: http://www.lydsy.com/JudgeOnline/problem.php?id=1798 Codevs: http://codevs.cn/problem/2216/ ...

最新文章

  1. 最美四门轿跑车斯柯达Coupe面世,CC也害怕。
  2. 信管专业c语言考什么,计算机信息管理专业卫生事业单位招聘考试笔试模拟题(十)...
  3. smarty基本语法之判断,循环语句
  4. [恢]hdu 2087
  5. 系统封装接口层 cmsis_os
  6. w10恢复出厂设置_笔记本电脑w10怎么恢复出厂设置
  7. uniapp-手写三级地区选择实现
  8. .chm文件是什么怎么打开?
  9. pc游戏平台_如何提高您在PC游戏中的目标
  10. ObjectARX 2016 安装心得
  11. 向北已上top.one交易所, 注册送40000个币,价值4000元。实名认证才能领更多 ,熊市福利!向北社区-区块链大神聚集地,邀请链接northx.cn/t/SKGH0
  12. libusb,libusbk,winusb的区别
  13. 你知道CAD软件中快速测量功能如何使用吗?
  14. 减库存怎么处理 java_java减库存
  15. Python中Tkinter模块的Canvas控件绘制jpg图片到指定区域
  16. #pragma DATA_SECTION的使用
  17. python网络安全怎么学_新手如何学习网络安全?
  18. 通俗易懂解释IP段192.168.1.0/24和192.168.0.0/16
  19. 虚拟机构建局域网用户和组远程
  20. Android 文件外/内部存储的获取各种存储目录路径

热门文章

  1. HDU (1575)Tr A ---矩阵快速幂
  2. linux下mkdir头文件_整理Linux下gcc编译中关于头文件与库文件搜索路径相关问题
  3. Python筛选中文字符(跟网上其他可能不一样)
  4. 高精度数取余(C\C++)
  5. 在html中超链接_HTML 超级链接详细讲解
  6. 第二十一讲 特征值和特征向量
  7. 想成为嵌入式程序员应知道的16个基本问题
  8. linux必会命令 - 后台运行程序 - nohup、
  9. 树莓派+驱动器 控制57步进电机运动
  10. ATM(BZOJ 1179)