[SHOI2015]脑洞治疗仪(恶心的线段树,区间最大子段和)
题目描述:
曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置。
为了简单起见,我们将大脑视作一个 01 序列。11代表这个位置的脑组织正常工作,00代表这是一块脑洞。
1 0 1 0 0 0 1 1 1 0
脑洞治疗仪修补某一块脑洞的基本工作原理就是将另一块连续区域挖出,将其中正常工作的脑组织填补在这块脑洞中。(所以脑洞治疗仪是脑洞的治疗仪?)
例如,用上面第88号位置到第1010号位置去修补第11号位置到第44号位置的脑洞,我们就会得到:
1 1 1 1 0 0 1 0 0 0
如果再用第11号位置到第44号位置去修补第88号位置到第1010号位置:
0 0 0 0 0 0 1 1 1 1
这是因为脑洞治疗仪会把多余出来的脑组织直接扔掉。
如果再用第77号位置到第1010号位置去填补第11号位置到第66号位置:
1 1 1 1 0 0 0 0 0 0
这是因为如果新脑洞挖出来的脑组织不够多,脑洞治疗仪仅会尽量填补位置比较靠前的脑洞。
假定初始时 SHTSC 并没有脑洞,给出一些挖脑洞和脑洞治疗的操作序列,你需要即时回答 SHTSC 的问题:在大脑某个区间中最大的连续脑洞区域有多大。
输入输出格式
输入格式:
第一行两个整数 n、m,表示 SHTSC 的大脑可分为从1到n编号的n个连续区域,有m个操作。
以下m行每行是下列三种格式之一:
0 l r:SHTSC 挖了一个范围为[l,r]的脑洞。
1 \(l_0\) \(r_0\) \(l_1\) \(r_1\):SHTSC 进行了一次脑洞治疗,用从\(l_0\) 到\(r_0\) 的脑组织修补\(l_1\)到\(r_1\) 的脑洞。
2 \(l\) \(r\):SHTSC 询问\([l,r]\)区间内最大的脑洞有多大。
上述区间均在\([1,n]\)范围内。
输出格式:
对于每个询问,输出一行一个整数,表示询问区间内最大连续脑洞区域有多大。
思路
很多题解都提到了GSS系列的最大连续子段和问题,那我就不说了,我只说这道题中我用到的一些奇妙的解法
1.反着定义
这道题要求的是最大连续0的长度,那么用最大子段和的话如果你按1走统计的就不是0,而是1,我们可以将1定义为-inf,0定义为1,再跑最大子段和即可
2.分开存
gss中要存一个区间和sum,但由于上面的定义形式,这玩意儿显然不能表示0(或1)的数量,我们可以用一个mix,专门存0或1的数量
大体思路:
0.首先,给1节点打上-inf的lazy标记,表示没有脑洞
1.对于0操作,区间覆盖,打lazy标记后直接修改即可
2.对于2操作,GSS标准查询即可
3.对于1操作,先求出l1,r1的脑组织数,再全挖成脑洞,之后填进l2,r2去即可(函数写成int式,优先填左区间,填完后返回剩余脑洞数)
代码:
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rii register int i
#define rij register int j
#define rs 262144
#define int long long
using namespace std;
struct tree{
long long lmax,rmax,sum,lazy,maxn,mix;
}x[1000005];
int n,m,p;
void pushdown(int nl,int nr,long long val,int bh)
{
int mid=(nl+nr)/2;
long long cd=mid-nl+1;
x[bh*2].lazy=val;
x[bh*2].lmax=val*cd;
x[bh*2].rmax=val*cd;
x[bh*2].sum=val*cd;
x[bh*2].maxn=val*cd;
x[bh*2].mix=(val%2)*cd;
x[bh*2+1].mix=(val%2)*cd;
x[bh*2+1].lazy=val;
x[bh*2+1].lmax=val*cd;
x[bh*2+1].rmax=val*cd;
x[bh*2+1].sum=val*cd;
x[bh*2+1].maxn=val*cd;
x[bh].lazy=0;
}
void fg(int l,int r,int nl,int nr,int bh)
{
if(l<nl)
{
l=nl;
}
if(r>nr)
{
r=nr;
}
if(x[bh].lazy==1)
{
return;
}
if(x[bh].lazy==-100000)
{
pushdown(nl,nr,x[bh].lazy,bh);
}
if(l==nl&&r==nr)
{
x[bh].lazy=1;
x[bh].sum=(r-l+1);
x[bh].lmax=(r-l+1);
x[bh].rmax=(r-l+1);
x[bh].maxn=(r-l+1);
x[bh].mix=(r-l+1);
return;
}
int mid=(nl+nr)/2;
if(l<=mid)
{
fg(l,r,nl,mid,bh*2);
}
if(r>=mid+1)
{
fg(l,r,mid+1,nr,bh*2+1);
}
x[bh].mix=x[bh*2].mix+x[bh*2+1].mix;
x[bh].sum=x[bh*2].sum+x[bh*2+1].sum;
x[bh].lmax=max(x[bh*2].lmax,x[bh*2].sum+x[bh*2+1].lmax);
x[bh].rmax=max(x[bh*2+1].rmax,x[bh*2+1].sum+x[bh*2].rmax);
x[bh].maxn=max(x[bh*2].maxn,max(x[bh*2+1].maxn,x[bh*2].rmax+x[bh*2+1].lmax));
}
int sum(int l,int r,int nl,int nr,int bh)
{
if(l<nl)
{
l=nl;
}
if(r>nr)
{
r=nr;
}
if(l==nl&&r==nr)
{
return x[bh].mix;
}
if(x[bh].lazy!=0&&nl!=nr)
{
pushdown(nl,nr,x[bh].lazy,bh);
}
int mid=(nl+nr)/2;
int ans=0;
if(l<=mid)
{
ans+=sum(l,r,nl,mid,bh*2);
}
if(r>=mid+1)
{
ans+=sum(l,r,mid+1,nr,bh*2+1);
}
return ans;
}
int add(int l,int r,int nl,int nr,int sl,int bh)
{
if(l<nl)
{
l=nl;
}
if(r>nr)
{
r=nr;
}
if(x[bh].lazy!=0)
{
pushdown(nl,nr,x[bh].lazy,bh);
}
if(l==nl&&r==nr&&sl>=(r-l+1))
{
sl-=x[bh].mix;
x[bh].mix=0;
x[bh].lmax=(-100000)*(r-l+1);
x[bh].rmax=(-100000)*(r-l+1);
x[bh].maxn=(-100000)*(r-l+1);
x[bh].sum=(-100000)*(r-l+1);
x[bh].lazy=-100000;
return sl;
}
int mid=(nl+nr)/2;
if(l<=mid&&sl!=0)
{
sl=add(l,r,nl,mid,sl,bh*2);
}
if(r>=mid+1&&sl!=0)
{
sl=add(l,r,mid+1,nr,sl,bh*2+1);
}
x[bh].mix=x[bh*2].mix+x[bh*2+1].mix;
x[bh].sum=x[bh*2].sum+x[bh*2+1].sum;
x[bh].lmax=max(x[bh*2].lmax,x[bh*2].sum+x[bh*2+1].lmax);
x[bh].rmax=max(x[bh*2+1].rmax,x[bh*2+1].sum+x[bh*2].rmax);
x[bh].maxn=max(x[bh*2].maxn,max(x[bh*2+1].maxn,x[bh*2].rmax+x[bh*2+1].lmax));
return sl;
}
tree query(int l,int r,int nl,int nr,int bh)
{
tree an,bn;
if(l<nl)
{
l=nl;
}
if(r>nr)
{
r=nr;
}
if(x[bh].lazy!=0)
{
pushdown(nl,nr,x[bh].lazy,bh);
}
if(nl==l&&nr==r)
{
an=x[bh];
return an;
}
int ltt=(nl+nr)/2;
if(l<=ltt&&r<=ltt)
{
return an=query(l,r,nl,ltt,bh*2);
}
if(r>ltt&&l>ltt)
{
return bn=query(l,r,ltt+1,nr,bh*2+1);
}
else
{
an=query(l,r,nl,ltt,bh*2);
bn=query(l,r,ltt+1,nr,bh*2+1);
an.maxn=max(an.maxn,max(bn.maxn,an.rmax+bn.lmax));
an.lmax=max(an.lmax,an.sum+bn.lmax);
an.rmax=max(bn.rmax,bn.sum+an.rmax);
an.sum=an.sum+bn.sum;
return an;
}
}
signed main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%lld%lld",&n,&m);
x[1].lazy=-100000;
for(rii=1;i<=m;i++)
{
int l,r;
scanf("%lld",&p);
if(p==0)
{
scanf("%lld%lld",&l,&r);
fg(l,r,1,rs,1);
}
if(p==2)
{
scanf("%lld%lld",&l,&r);
tree ans=query(l,r,1,rs,1);
if(ans.maxn<0)
{
ans.maxn=0;
}
printf("%lld\n",ans.maxn);
}
if(p==1)
{
int l1,l2,r1,r2;
scanf("%lld%lld%lld%lld",&l2,&r2,&l1,&r1);
int ltt=sum(l2,r2,1,rs,1);
ltt=(r2-l2+1)-ltt;
fg(l2,r2,1,rs,1);
if(ltt>(r2-l2+1))
{
ltt=r2-l2+1;
}
add(l1,r1,1,rs,ltt,1);
}
}
}
[SHOI2015]脑洞治疗仪(恶心的线段树,区间最大子段和)的更多相关文章
- 【BZOJ4592】[Shoi2015]脑洞治疗仪 线段树
[BZOJ4592][Shoi2015]脑洞治疗仪 Description 曾经发明了自动刷题机的发明家SHTSC又公开了他的新发明:脑洞治疗仪--一种可以治疗他因为发明而日益增大的脑洞的神秘装置. ...
- 【题解】Luogu P4344 [SHOI2015]脑洞治疗仪
原题传送门:P4344 [SHOI2015]脑洞治疗仪 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 珂朵莉树好题啊 我一开始一直Re65 后来重构代码就ac了,或许是rp问题 ...
- 「模板」 线段树——区间乘 && 区间加 && 区间求和
「模板」 线段树--区间乘 && 区间加 && 区间求和 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long l ...
- POJ 2528 Mayor's posters 【区间离散化+线段树区间更新&&查询变形】
任意门:http://poj.org/problem?id=2528 Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total S ...
- POJ 2823 Sliding Window 线段树区间求和问题
题目链接 线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过. 注意这道题不是求三个数的最大值最小值,是求k个的. 本题数据量较大,不能用N建树,用n建树. 还有一种做法是单调 ...
- CF444C. DZY Loves Colors[线段树 区间]
C. DZY Loves Colors time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- HDU 4509 湫湫系列故事——减肥记II(线段树-区间覆盖 或者 暴力技巧)
http://acm.hdu.edu.cn/showproblem.php?pid=4509 题目大意: 中文意义,应该能懂. 解题思路: 因为题目给的时间是一天24小时,而且还有分钟.为了解题方便, ...
- POJ 3667 Hotel(线段树 区间合并)
Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...
- HDU 1698 Just a Hook(线段树 区间替换)
Just a Hook [题目链接]Just a Hook [题目类型]线段树 区间替换 &题解: 线段树 区间替换 和区间求和 模板题 只不过不需要查询 题里只问了全部区间的和,所以seg[ ...
- HDU 1556 Color the ball(线段树区间更新)
Color the ball 我真的该认真的复习一下以前没懂的知识了,今天看了一下线段树,以前只会用模板,现在看懂了之后,发现还有这么多巧妙的地方,好厉害啊 所以就应该尽量搞懂 弄明白每个知识点 [题 ...
随机推荐
- js之箭头函数
原文 ES6标准新增了一种新的函数:Arrow Function(箭头函数). 为什么叫Arrow Function?因为它的定义用的就是一个箭头: x => x * x 上面的箭头函数相当于: ...
- Spring课程 Spring入门篇 4-6 Spring bean装配之基于java的容器注解说明--@ImportResource和@Value java与properties文件交互
1 解析 1.1 这两个注解应用在什么地方 1.2 应用方式 1.3 xml方式实现取值 2 代码演练 2.1 @ImportResource和@Value代码演练 1 解析 1.1 这两个注解应用在 ...
- Steps of source code change to executable application
程序运行的整个过程,学习一下 源代码 (source code) → 预处理器 (preprocessor) → 编译器 (compiler) → 汇编程序 (assembler) → 目标代码 (o ...
- C++异步编程资料汇集贴
C++异步编程 http://www.cnblogs.com/zjjcy/archive/2012/03/18/2404214.htmlhttp://www.cnblogs.com/zjjcy/arc ...
- matlab练习程序(单源最短路径Bellman-Ford)
该算法可以用来解决一般(边的权值为负)的单源最短路径问题,而dijkstra只能解决权值非负的情况. 此算法使用松弛技术,对每一个顶点,逐步减少源到该顶点的路径的估计值,直到达到最短的路径. 算法运算 ...
- 仿照jQuery写一个关于选择器的框架(带了注释,请多多指教~)
var select = (function () { //这是一个异常与捕获的代码,它表示的意思是:如果push方法出现了错误那么就需要重写push方法 try { //这边是自己模拟一个场景,来使 ...
- matlab中repmat函数的用法(堆叠矩阵)
matlab中repmat函数的用法 B = repmat(A,m,n) B = repmat(A,[m n]) B = repmat(A,[m n p...]) 这是一个处理大矩阵且内容有重复时使用 ...
- JDBC操作数据库的基本步骤:
JDBC操作数据库的基本步骤: 1)加载(注册)数据库驱动(到JVM). 2)建立(获取)数据库连接. 3)创建(获取)数据库操作对象. 4)定义操作的SQL语句. 5)执行数据库操作. 6)获取并操 ...
- ring0 关于SSDTHook使用的绕过页面写保护的原理与实现
原博:http://www.cnblogs.com/hongfei/archive/2013/06/18/3142162.html 为了安全起见,Windows XP及其以后的系统将一些重要的内存页设 ...
- flume-ng 自定义sink消费flume source
如何从一个已经存在的Flume source消费数据 1.下载flume wget http://www.apache.org/dist/flume/stable/apache-flume-1.5.2 ...