题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4592

题意概述:
需要维护一个01序列A,一开始A全部都是1。支持如下操作:
  1.将区间[l,r]变成0。
  2.将区间[l0,r0]变成0,用其中原来1的个数去填补[l1,r1]中的0,当1的数量过多的时候剩余的1会被丢弃;当1的数量不足的时候从左到右依次填充0。
  3.询问区间[l,r]中最长的0串长度。
N,M<=200000.

我就直接把考试的时候写的东西弄上来了:

  首先建立一颗序列线段树,维护01序列,支持求和操作,同时维护最长序列。

  对于1操作,直接区间赋值为0。

  对于2操作,首先对[l0,r0]对1求和,记为x,然后赋值为0。然后在区间[l1,r1]中找到第一个0数量大于等于x的位置(实在没有就是r1),然后区间赋值。这一步可以用前缀和的思想,先求[1,l1-1](注意先对[l0,r0]操作)中的0数量y,然后就可以在线段树里直接查找第x+y个0的位置,最后的结果和r1比较,取较小值。

  对于3操作,首先在线段树中维护区间左起最长、右起最长、区间最长的0串长度,查询的时候:要查询的区间完全在左半边或者右半边,直接递归处理;当查询区间跨越当前区间的中点,左右区间右起最长,左起最长各自与查询长度取min相加作为一个答案,递归到左右区间,三个答案取最大值;询问区间包含当前区间,直接返回区间最长0串长度(实际上处理的思路就是分治,跨越中间的,左边的,右边的)。

  于是一通维护下来相当于要维护的东西有:1数量之和,0数量之和,0区间最长串三件套。

  时间复杂度O(MlogN)

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std; int N,M;
struct segment_tree{
static const int maxn=;
int rt,np,lc[maxn],rc[maxn],s0[maxn],s1[maxn],ml[maxn],mr[maxn],mm[maxn],flag[maxn];
segment_tree(){ rt=np=; }
void pushup(int now,int L,int R){
int m=L+R>>;
s0[now]=s0[lc[now]]+s0[rc[now]];
s1[now]=s1[lc[now]]+s1[rc[now]];
ml[now]=max(ml[lc[now]],ml[lc[now]]==m-L+?ml[lc[now]]+ml[rc[now]]:);
mr[now]=max(mr[rc[now]],mr[rc[now]]==R-m?mr[rc[now]]+mr[lc[now]]:);
mm[now]=max(mr[lc[now]]+ml[rc[now]],max(mm[lc[now]],mm[rc[now]]));
}
void pushdown(int now,int L,int R){
if(flag[now]==-) return;
int m=L+R>>;
if(flag[now]==){
ml[lc[now]]=mr[lc[now]]=mm[lc[now]]=m-L+;
s0[lc[now]]=m-L+,s1[lc[now]]=,flag[lc[now]]=;
ml[rc[now]]=mr[rc[now]]=mm[rc[now]]=R-m;
s0[rc[now]]=R-m,s1[rc[now]]=,flag[rc[now]]=;
}
else{
ml[lc[now]]=mr[lc[now]]=mm[lc[now]]=;
s0[lc[now]]=,s1[lc[now]]=m-L+,flag[lc[now]]=;
ml[rc[now]]=mr[rc[now]]=mm[rc[now]]=;
s0[rc[now]]=,s1[rc[now]]=R-m,flag[rc[now]]=;
}
flag[now]=-;
}
void build(int &now,int L,int R){
now=++np;
lc[now]=rc[now]=,s0[now]=ml[now]=mr[now]=mm[now]=,s1[now]=R-L+,flag[now]=-;
if(L==R) return;
int m=L+R>>;
build(lc[now],L,m); build(rc[now],m+,R);
}
void update(int now,int L,int R,int A,int B,int v){
if(A<=L&&R<=B){
if(v==){
ml[now]=mr[now]=mm[now]=R-L+;
s0[now]=R-L+,s1[now]=,flag[now]=;
}
else{
ml[now]=mr[now]=mm[now]=;
s0[now]=,s1[now]=R-L+,flag[now]=;
}
return;
}
pushdown(now,L,R);
int m=L+R>>;
if(B<=m) update(lc[now],L,m,A,B,v);
else if(A>m) update(rc[now],m+,R,A,B,v);
else update(lc[now],L,m,A,B,v),update(rc[now],m+,R,A,B,v);
pushup(now,L,R);
}
int query_s(int now,int L,int R,int A,int B,int v){
if(A<=L&&R<=B) return v?s1[now]:s0[now];
pushdown(now,L,R);
int m=L+R>>;
if(B<=m) return query_s(lc[now],L,m,A,B,v);
if(A>m) return query_s(rc[now],m+,R,A,B,v);
return query_s(lc[now],L,m,A,B,v)+query_s(rc[now],m+,R,A,B,v);
}
int query_p(int now,int L,int R,int k){
if(L==R) return L;
pushdown(now,L,R);
int m=L+R>>;
if(k<=s0[lc[now]]) return query_p(lc[now],L,m,k);
return query_p(rc[now],m+,R,k-s0[lc[now]]);
}
int query_mm(int now,int L,int R,int A,int B){
if(A<=L&&R<=B) return mm[now];
pushdown(now,L,R);
int m=L+R>>;
if(B<=m) return query_mm(lc[now],L,m,A,B);
if(A>m) return query_mm(rc[now],m+,R,A,B);
int re=min(m-A+,mr[lc[now]])+min(B-m,ml[rc[now]]);
return max(re,max(query_mm(lc[now],L,m,A,m),query_mm(rc[now],m+,R,m+,B)));
}
}st; void work()
{
scanf("%d%d",&N,&M);
st.build(st.rt,,N);
int op,l0,r0,l1,r1,x,y,p;
for(int i=;i<=M;i++){
scanf("%d",&op);
if(op==){
scanf("%d%d",&l0,%r0);
st.update(st.rt,,N,l0,r0,);
}
else if(op==){
scanf("%d%d%d%d",&l0,&r0,&l1,&r1);
x=st.query_s(st.rt,,N,l0,r0,);
if(!x) continue;
st.update(st.rt,,N,l0,r0,);
y=l1==?:st.query_s(st.rt,,N,,l1-,);
p=min(r1,st.query_p(st.rt,,N,y+x));
st.update(st.rt,,N,l1,p,);
}
else if(op==){
scanf("%d%d",&l0,&r0);
printf("%d\n",st.query_mm(st.rt,,N,l0,r0));
}
}
}
int main()
{
work();
return ;
}

BZOJ 4592 SHOI2015 脑洞治疗仪 线段树的更多相关文章

  1. 【BZOJ4592】[Shoi2015]脑洞治疗仪 线段树

    [BZOJ4592][Shoi2015]脑洞治疗仪 Description 曾经发明了自动刷题机的发明家SHTSC又公开了他的新发明:脑洞治疗仪--一种可以治疗他因为发明而日益增大的脑洞的神秘装置. ...

  2. [BZOJ4592][SHOI2015]脑洞治疗仪(线段树)

    线段树基础操作题,唯一需要思考下的是将区间的前k个0覆盖为1. 线段树上二分,先递归到左子树覆盖,回溯时返回还剩多少个0未被覆盖,在根据这个信息递归到右子树.注意特判k=0的情况. 要维护的信息有:区 ...

  3. 【BZOJ-4592】脑洞治疗仪 线段树

    4592: [Shoi2015]脑洞治疗仪 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 69  Solved: 38[Submit][Status] ...

  4. bzoj 4592(洛谷 4344) [Shoi2015]脑洞治疗仪——线段树上二分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4592 1操作就是用线段树来二分找到第一个有 k 个0的位置. 在洛谷上A了,与暴力和网上题解 ...

  5. 【题解】Luogu P4344 [SHOI2015]脑洞治疗仪

    原题传送门:P4344 [SHOI2015]脑洞治疗仪 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 珂朵莉树好题啊 我一开始一直Re65 后来重构代码就ac了,或许是rp问题 ...

  6. [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并)

    [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并) 题面 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1 ...

  7. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

  8. [SHOI2015]脑洞治疗仪(恶心的线段树,区间最大子段和)

    题目描述: 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪--一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见,我们将大脑视作一个 01 序列.11代表这个位 ...

  9. BZOJ4592 SHOI2015脑洞治疗仪(线段树)

    考虑需要资瓷哪些操作:区间赋值为0:统计区间1的个数:将区间前k个0变为1:询问区间最长全0子串.于是线段树维护区间1的个数.0的个数.最长前缀后缀全0子串即可.稍微困难的是用一个log实现将区间前k ...

随机推荐

  1. 用JS实现一个时钟的效果

    (效果图) 分两步进行的. 第一步:  要得到现在的 时 分 秒 但是这里面有一个小玄机 . 比如现在是 9点整      时针指向 9 是没错的 但是如果现在是 9点半   时针应该指向的是 9到1 ...

  2. 使用补丁破解IntelliJ IDEA 2017收费版本(转)

    1. 首先去官网http://www.jetbrains.com/idea/download/#section=windows下载Ultimate版(注意不是community版)下载并安装.一定要记 ...

  3. Python基础—11-面向对象(01)

    面向对象 面向对象 与面向过程对比: 面向过程:数学逻辑的映射,学会做个好员工 面向对象:生活逻辑的映射,学会做个好领导 生活实例: 类: 人 手机 电脑 对象: 我的手机.女朋友的手机 你的那部T4 ...

  4. ssm整合实现注册与登录功能

    最简洁易懂的SSM整合源码都在这里了 激情提示: 1.本项目是用IDEA编写的,不管你是习惯何种ide工具,那也只是工具而已,源代码才是本质 2.本项目只拥有注册和登录功能,简易的功能和详细的注释,是 ...

  5. 关于ECharts内存泄漏问题

    最近使用websocket加ECharts做了一个实时监控的功能,发现了一个比较严重的问题,就是浏览器运行一段时间就会非常卡,之前在ECharts官网运行官方实例“动态数据 + 时间坐标轴”时,也遇到 ...

  6. html+php上传图片文件到服务器

    html+php上传图片文件到服务器 一.html代码 <body> <form action="" method="post" enctyp ...

  7. STM32CubeMx配置正交编码器遇到的问题

    配置时参考了这个哥们的方法: http://www.eemaker.com/stm32cubemx-encoder.html 然后我的配置是这样的 配置是没有问题. 调用时出现了问题. 由于配置完了, ...

  8. 【Markdown】Markdown的使用(自用)

    # 欢迎使用 Cmd Markdown 编辑阅读器 我们理解您需要更便捷更高效的工具记录思想,整理笔记.知识,并将其中承载的价值传播给他人,Cmd Markdown 是我们给出的答案 -- 我们为记录 ...

  9. go学习笔记-语言指针

    语言指针 定义及使用 变量是一种使用方便的占位符,用于引用计算机内存地址.取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址. 一个指针变量指向了一个值的内存地址.类似于变量和常量, ...

  10. java图片识别 [Tesseract-OCR]

    以下链接包含,安装包及程序运行需要的jar 包,中文资源包. 中文包使用方式:找到tessdata安装目录(我本地:C:\Program Files (x86)\Tesseract-OCR\tessd ...