BZOJ 1858【线段树】
题意:
0 a b 把 [a, b] 区间内的所有数全变成0
1 a b 把 [a, b] 区间内的所有数全变成1
2 a b 把 [a,b] 区间内的所有数全部取反
3 a b 询问 [a, b] 区间内总共有多少个1
4 a b 询问 [a, b] 区间内最多有多少个连续的1
思路:
首先 线段树 可以搞个标记 flag 是否都是 1(flag=1)/0(flag=-1) LAZY一下
询问区间有多少个 1 ,那就是求和而已?
询问区间最多有多少个连续的1 ?
主要是区间合并的时候要判断
左儿子的Right_Num ==1 && 右儿子的Left_Num ==1 然后还要算下这段区间,和最大值比较。
so,我再搞两个值,一个结点区间的 左端点 连续为 1 的距离,右端点 连续为1 的距离
后面发现还要再添,一个结点区间的 左端点 连续为 0 的距离,右端点 连续为0 的距离,方便反转
现在发现,线段树 就是个 大模拟= =、好像所有的东西都是大模拟。。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL; const int N=1e5+10; struct Seg{
int Left,Right;
int Flag; //标记
int Sum; //区间1的个数
int Max_Len; //区间 连续 1的 最长长度
int Left_Len1,Right_Len1; //区间左端点连续为1的距离,右端点 连续为1 的距离
int Left_Len0,Right_Len0; //区间左端点连续为0的距离,右端点 连续为0 的距离
}q[N*4]; void Pushdown(int num)
{
if(!q[num].Flag) return;
if(q[num].Flag==1)
{
q[num<<1].Sum=q[num<<1].Left_Len1=q[num<<1].Right_Len1=q[num<<1].Max_Len=(q[num<<1].Right-q[num<<1].Left+1);
q[num<<1].Left_Len0=q[num<<1].Right_Len0=0;
q[num<<1].Flag=1; q[num<<1|1].Sum=q[num<<1|1].Left_Len1=q[num<<1|1].Right_Len1=q[num<<1|1].Max_Len=(q[num<<1|1].Right-q[num<<1|1].Left+1);
q[num<<1|1].Left_Len0=q[num<<1|1].Right_Len0=0;
q[num<<1|1].Flag=1; q[num].Flag=0;
}
else
{
q[num<<1].Sum=q[num<<1].Left_Len1=q[num<<1].Right_Len1=q[num<<1].Max_Len=0;
q[num<<1].Left_Len0=q[num<<1].Right_Len0=(q[num<<1].Right-q[num<<1].Left+1);
q[num<<1].Flag=-1; q[num<<1|1].Sum=q[num<<1|1].Left_Len1=q[num<<1|1].Right_Len1=q[num<<1|1].Max_Len=0;
q[num<<1|1].Left_Len0=q[num<<1|1].Right_Len0=(q[num<<1|1].Right-q[num<<1|1].Left+1);
q[num<<1|1].Flag=-1; q[num].Flag=0;
}
} void Pushup(int num)
{
if(q[num].Sum==(q[num].Right-q[num].Left+1))
{
q[num].Flag=1;
q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum;
q[num].Left_Len0=q[num].Right_Len0=0;
}
else if(!q[num].Sum)
{
q[num].Flag=-1;
q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum;
q[num].Left_Len0=q[num].Right_Len0=q[num].Right-q[num].Left+1;
}
else
{
q[num].Flag=0; int Max=max(q[num<<1].Max_Len,q[num<<1|1].Max_Len);
Max=max(q[num<<1].Right_Len1+q[num<<1|1].Left_Len1,Max);
q[num].Max_Len=Max; if(q[num<<1].Left_Len1==(q[num<<1].Right-q[num<<1].Left+1))
{
q[num].Left_Len1=q[num<<1].Left_Len1+q[num<<1|1].Left_Len1;
q[num].Left_Len0=0;
}
else
{
q[num].Left_Len1=q[num<<1].Left_Len1; if(q[num<<1].Left_Len0==(q[num<<1].Right-q[num<<1].Left+1))
q[num].Left_Len0=q[num<<1].Left_Len0+q[num<<1|1].Left_Len0;
else
q[num].Left_Len0=q[num<<1].Left_Len0;
} if(q[num<<1|1].Right_Len1==(q[num<<1|1].Right-q[num<<1|1].Left+1))
{
q[num].Right_Len1=q[num<<1].Right_Len1+q[num<<1|1].Right_Len1;
q[num].Right_Len0=0;
}
else
{
q[num].Right_Len1=q[num<<1|1].Right_Len1;
if(q[num<<1|1].Right_Len0==(q[num<<1|1].Right-q[num<<1|1].Left+1))
q[num].Right_Len0=q[num<<1].Right_Len0+q[num<<1|1].Right_Len0;
else
q[num].Right_Len0=q[num<<1|1].Right_Len0;
}
}
} void Build(int num,int Left,int Right)
{
q[num].Left=Left;q[num].Right=Right;
if(Left==Right)
{
scanf("%d",&q[num].Sum);
if(q[num].Sum==1) q[num].Flag=1;
else q[num].Flag=-1;
q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum;
q[num].Left_Len0=q[num].Right_Len0=1-q[num].Sum;
return;
}
int Mid=(q[num].Left+q[num].Right)>>1;
Build(num<<1,Left,Mid);
Build(num<<1|1,Mid+1,Right); q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
Pushup(num);
} void Update1(int num,int Left,int Right)
{
if(q[num].Left>=Left && q[num].Right<=Right)
{
q[num].Flag=-1;
q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum=0;
q[num].Left_Len0=q[num].Right_Len0=q[num].Right-q[num].Left+1;
return;
}
Pushdown(num); int Mid=(q[num].Left+q[num].Right)>>1;
if(Mid>=Right) Update1(num<<1,Left,Right);
else if(Mid<Left) Update1(num<<1|1,Left,Right);
else
{
Update1(num<<1,Left,Mid);
Update1(num<<1|1,Mid+1,Right);
} q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
Pushup(num);
} void Update2(int num,int Left,int Right)
{
if(q[num].Left>=Left && q[num].Right<=Right)
{
q[num].Flag=1;
q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum=(q[num].Right-q[num].Left+1);
q[num].Left_Len0=q[num].Right_Len0=0;
return;
} Pushdown(num); int Mid=(q[num].Left+q[num].Right)>>1;
if(Mid>=Right) Update2(num<<1,Left,Right);
else if(Mid<Left) Update2(num<<1|1,Left,Right);
else
{
Update2(num<<1,Left,Mid);
Update2(num<<1|1,Mid+1,Right);
} q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
Pushup(num);
} void Update3(int num,int Left,int Right)
{
if(q[num].Left>=Left && q[num].Right<=Right && (q[num].Sum==0||q[num].Sum==(q[num].Right-q[num].Left+1)))
{
if(q[num].Sum==(q[num].Right-q[num].Left+1)) q[num].Flag=-1;
else q[num].Flag=1;
q[num].Max_Len=q[num].Sum=q[num].Right-q[num].Left+1-q[num].Sum;
swap(q[num].Right_Len0,q[num].Right_Len1);
swap(q[num].Left_Len0,q[num].Left_Len1);
return;
} Pushdown(num); int Mid=(q[num].Left+q[num].Right)>>1;
if(Mid>=Right) Update3(num<<1,Left,Right);
else if(Mid<Left) Update3(num<<1|1,Left,Right);
else
{
Update3(num<<1,Left,Mid);
Update3(num<<1|1,Mid+1,Right);
} q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
Pushup(num);
} int Query(int num,int Left,int Right)
{
if(q[num].Left>=Left && q[num].Right<=Right)
return q[num].Sum;
Pushdown(num);
int Mid=(q[num].Left+q[num].Right)>>1;
if(Mid>=Right)
return Query(num<<1,Left,Right);
else if(Mid<Left)
return Query(num<<1|1,Left,Right);
else
return Query(num<<1,Left,Mid)+Query(num<<1|1,Mid+1,Right);
} int MaxLen(int num,int Left,int Right)
{
if(q[num].Left>=Left && q[num].Right<=Right) return q[num].Max_Len;
Pushdown(num);
int Mid=(q[num].Left+q[num].Right)>>1;
if(Mid>=Right) return MaxLen(num<<1,Left,Right);
else if(Mid<Left) return MaxLen(num<<1|1,Left,Right);
else
{
int Len1=MaxLen(num<<1,Left,Mid);
int Len2=MaxLen(num<<1|1,Mid+1,Right);
int Len3=min(q[num<<1].Right_Len1,Mid-Left+1) + min(q[num<<1|1].Left_Len1,Right-Mid);
return max(Len1,max(Len2,Len3));
}
} int main()
{
int n,m,x;
int Left,Right;
scanf("%d%d",&n,&m);
Build(1,1,n); while(m--){
scanf("%d%d%d",&x,&Left,&Right);
Left++;Right++;
switch(x)
{
case 0: { Update1(1,Left,Right); break;}
case 1: { Update2(1,Left,Right); break;}
case 2: { Update3(1,Left,Right); break;}
case 3: { printf("%d\n",Query(1,Left,Right)); break;}
case 4: { printf("%d\n",MaxLen(1,Left,Right)); break;}
}
}
return 0;
}
BZOJ 1858【线段树】的更多相关文章
- BZOJ 1858 线段树
标记会重叠需要判断. #include <bits/stdc++.h> using namespace std; inline int Max(int x,int y) {return x ...
- BZOJ 1798 (线段树||分块)的标记合并
我原来准备做方差的.. 结果发现不会维护两个标记.. 就是操作变成一个 a*x+b ,每次维护a , b 即可 加的时候a=1 ,b=v 乘的时候a=v ,b=0 #include <cstdi ...
- HYSBZ 1858 线段树 区间合并
//Accepted 14560 KB 1532 ms //线段树 区间合并 /* 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[ ...
- bzoj 3999 线段树区间提取 有序链剖
看错题目了,想成每个城市都可以买一个东西,然后在后面的某个城市卖掉,问最大收益.这个可以类似维护上升序列的方法在O(nlog^3n)的时间复杂度内搞定 这道题用到的一些方法: 1. 可以将有关的线段提 ...
- bzoj 3211 线段树
开方操作最多进行5次就可以把出现的任何数变成1. 所以用线段树暴力修改,以后修改时只需看一下是否当前区间都是0或1,如果是那么就直接返回. /***************************** ...
- bzoj 1018 线段树维护连通性
本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护. 对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边 ...
- bzoj 3212 线段树
裸的线段树 /************************************************************** Problem: User: BLADEVIL Langua ...
- bzoj 2120 线段树套平衡树
先吐下槽,改了快一个小时,最后发现是SBT的delete写错了,顿时就有想死的心..... 首先对于这道题,我们应该先做一下他的小问题,bzoj1878,虽然和这道题几乎一点关系没有, 但是能给我们一 ...
- bzoj 1901 线段树套平衡树+二分答案查询
我们就建一颗线段树,线段树的每一个节点都是一颗平衡树,对于每个询问来说,我们就二分答案, 查询每个二分到的mid在这个区间里的rank,然后就行了 /************************* ...
- BZOJ 1012 线段树||单调队列
非常裸的线段树 || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件 ...
随机推荐
- winform 添加帮助按钮
1. 添加提示信息 新建个窗体项目,项目名称为WinFormUI,解决方案名称为WinFormWithHelpDoc.删除默认创建的Form1,新建窗体MainForm,设置相关属性.我们要完成的效果 ...
- Python基础-random模块及随机生成11位手机号
import random # print(random.random()) # 随机浮点数,默认取0-1,不能指定范围# print(random.randint(1, 20)) # 随机整数,顾头 ...
- Java微信开发_00_资源汇总贴
1.微信公众平台技术文档(https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432) 2.微信企业号开发接口文档(ht ...
- 截取URL参数的方法
1,有点小瑕疵,双问号会截取不到第一个参数 function GetQueryString(name){ var reg = new RegExp("(^|&)"+ nam ...
- 【leetcode刷题笔记】Pow(x, n)
Implement pow(x, n). 题解:注意两点: 普通的递归把n降为n-1会超时,要用二分的方法,每次把xn = x[n/2] * x[n/2] * xn-[n/2]*2, [n/2]表示n ...
- FFmpeg 基本用法--此文转载,作为笔记
v 容器(Container) v 容器就是一种文件(封装)格式,比如flv.mkv.ts.mp4.rmvb.avi等.包含下面5种流以及文件头信息. v 流(Stream) v 是一种视频数 ...
- noip前打板子 qwq
在某咕上打了一晚上的模板 感觉还好... #include<bits/stdc++.h> #define LL long long using namespace std; inline ...
- bzoj 4773: 负环 floyd
题目: 对于边带权的有向图,找出一个点数最小的环,使得环上的边权和为负. 2 <= n <= 300. 题解: 我们可以考虑从小到大枚举答案. 然后每次枚举更大的答案的时候就从当前的较小的 ...
- Azure上部署Barracuda WAF集群 --- 1
公有云上的第一层防护,一般要采用Proxy模式的安全设备. 梭子鱼的WAF是最早支持Azure China公有云的安全设备. 本文记录了在Azure上安装部署Barracuda的过程.下面就是安装部署 ...
- linux下go的动态链接库的使用
转自:http://blog.csdn.net/xtxy/article/details/21328143 在使用lua进行服务器端游戏逻辑开发时,发现了LUA的各种不方便的地方,不能编译检查,不能断 ...