bzoj5312 冒险(吉司机线段树)题解
题意:
已知\(n\)个数字,进行以下操作:
- \(1.\)区间\([L,R]\) 按位与\(x\)
- \(2.\)区间\([L,R]\) 按位或\(x\)
- \(3.\)区间\([L,R]\) 询问最大值
思路:
吉司机线段树。
我们按位考虑,维护区间或\(\_or\)和区间与\(\_and\),那么得到区间非公有的\(1\)为\((\_or \oplus \_and)\),那么如果对所有的非公有的\(1\)影响都一样就不会对最大值有影响,那么就直接打标机,否则继续往下更新。即
\]
时就直接打标记。
代码:
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int maxn = 2e5 + 5;
const int MAXM = 3e6;
const ll MOD = 998244353;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
#define lson (rt << 1)
#define rson (rt << 1 | 1)
inline bool read(int &num){
char in;
bool IsN=false;
in = getchar();
if(in == EOF) return false;
while(in != '-' && (in < '0' || in > '9')) in = getchar();
if(in == '-'){ IsN = true; num = 0;}
else num = in - '0';
while(in = getchar(),in >= '0' && in <= '9'){
num *= 10, num += in-'0';
}
if(IsN) num = -num;
return true;
}
int a[maxn], all = (1 << 21) - 1;
int _or[maxn << 2], _and[maxn << 2], Max[maxn << 2];
int lazya[maxn << 2], lazyo[maxn << 2];
inline void pushup(int rt){
_or[rt] = _or[lson] | _or[rson];
_and[rt] = _and[lson] & _and[rson];
Max[rt] = max(Max[lson], Max[rson]);
}
inline void pushdown(int rt, int l, int r){
int m = (l + r) >> 1;
if(lazya[rt] != all){
Max[lson] &= lazya[rt];
Max[rson] &= lazya[rt];
_or[lson] &= lazya[rt];
_or[rson] &= lazya[rt];
_and[lson] &= lazya[rt];
_and[rson] &= lazya[rt];
lazya[lson] &= lazya[rt];
lazya[rson] &= lazya[rt];
lazyo[lson] &= lazya[rt];
lazyo[rson] &= lazya[rt];
lazya[rt] = all;
}
if(lazyo[rt] != 0){
Max[lson] |= lazyo[rt];
Max[rson] |= lazyo[rt];
_or[lson] |= lazyo[rt];
_or[rson] |= lazyo[rt];
_and[lson] |= lazyo[rt];
_and[rson] |= lazyo[rt];
lazya[lson] |= lazyo[rt];
lazya[rson] |= lazyo[rt];
lazyo[lson] |= lazyo[rt];
lazyo[rson] |= lazyo[rt];
lazyo[rt] = 0;
}
}
void build(int l, int r, int rt){
lazya[rt] = all, lazyo[rt] = 0;
if(l == r){
_and[rt] = _or[rt] = Max[rt] = a[l];
return;
}
int m = (l + r) >> 1;
build(l, m, lson);
build(m + 1, r, rson);
pushup(rt);
}
void update(int L, int R, int l, int r, int op, int x, int rt){
if(L <= l && R >= r){
if(op == 1){ //&
if(((_or[rt] ^ _and[rt]) & x) == 0 || ((_or[rt] ^ _and[rt]) & x) == (_or[rt] ^ _and[rt])){
Max[rt] &= x;
_or[rt] &= x;
_and[rt] &= x;
lazya[rt] &= x;
lazyo[rt] &= x;
return;
}
}
else{ //|
if(((_or[rt] ^ _and[rt]) & x) == 0 || ((_or[rt] ^ _and[rt]) & x) == (_or[rt] ^ _and[rt])){
Max[rt] |= x;
_or[rt] |= x;
_and[rt] |= x;
lazya[rt] |= x;
lazyo[rt] |= x;
return;
}
}
}
int m = (l + r) >> 1;
pushdown(rt, l, r);
if(L <= m)
update(L, R, l, m, op, x, lson);
if(R > m)
update(L, R, m + 1, r, op, x, rson);
pushup(rt);
}
int query(int L, int R, int l, int r, int rt){
if(L <= l && R >= r){
return Max[rt];
}
pushdown(rt, l, r);
int m = (l + r) >> 1, MAX = -INF;
if(L <= m)
MAX = max(MAX, query(L, R, l, m, lson));
if(R > m)
MAX = max(MAX, query(L, R, m + 1, r, rson));
return MAX;
}
int main(){
int n, m;
read(n), read(m);
for(int i = 1; i <= n; i++) read(a[i]);
build(1, n, 1);
while(m--){
int op, l, r, x;
read(op), read(l), read(r);
if(op < 3) read(x);
if(op < 3){
update(l, r, 1, n, op, x, 1);
}
else{
printf("%d\n", query(l, r, 1, n, 1));
}
}
return 0;
}
bzoj5312 冒险(吉司机线段树)题解的更多相关文章
- bzoj4355 Play with sequence(吉司机线段树)题解
题意: 已知\(n\)个数字,进行以下操作: \(1.\)区间\([L,R]\) 赋值为\(x\) \(2.\)区间\([L,R]\) 赋值为\(max(a[i] + x, 0)\) \(3.\)区间 ...
- bzoj4695 最假女选手(势能线段树/吉司机线段树)题解
题意: 已知\(n\)个数字,进行以下操作: \(1.\)给一个区间\([L,R]\) 加上一个数\(x\) \(2.\)把一个区间\([L,R]\) 里小于\(x\) 的数变成\(x\) \(3.\ ...
- BZOJ4355: Play with sequence(吉司机线段树)
题意 题目链接 Sol 传说中的吉司机线段树??感觉和BZOJ冒险那题差不多,就是强行剪枝... 这题最坑的地方在于对于操作1,$C >= 0$, 操作2中需要对0取max,$a[i] > ...
- HDU - 5306 Gorgeous Sequence (吉司机线段树)
题目链接 吉司机线段树裸题... #include<bits/stdc++.h> using namespace std; typedef long long ll; ,inf=0x3f3 ...
- UVALive - 4108 SKYLINE (吉司机线段树)
题目链接 题意:在一条直线上依次建造n座建筑物,每座建筑物建造完成后询问它在多长的部分是最高的. 比较好想的方法是用线段树分别维护每个区间的最小值mi和最大值mx,当建造一座高度为x的建筑物时,若mi ...
- HDU - 6315 吉司机线段树
题意:给出a,b数组,区间上两种操作,给\(a[L,R]\)+1s,或者求\(\sum_{i=l}^{r}a_i/b_i\) 一看就知道是吉司机乱搞型线段树(低配版),暴力剪枝就好 维护区间a的最大值 ...
- BZOJ5312 冒险(势能线段树)
BZOJ题目传送门 表示蒟蒻并不能一眼看出来这是个势能线段树. 不过仔细想想也并非难以理解,感性理解一下,在一个区间里又与又或,那么本来不相同的位也会渐渐相同,线段树每个叶子节点最多修改\(\log ...
- HDU 5306 吉司机线段树
思路: 后面nlogn的部分是伪证... 大家可以构造数据证明是这是nlog^2n的啊~ 吉老司机翻车了 //By SiriusRen #include <cstdio> #include ...
- hdu6521 吉司机线段树
http://acm.hdu.edu.cn/showproblem.php?pid=6521 待填 代码 #include<bits/stdc++.h> #define ls o<& ...
随机推荐
- 十一、UART&TTY驱动
Linux系统中UART驱动和TTY驱动两者有着紧密的关系,它们不像I2C和SPI驱动是单独一个模块,分析时应当将它们看成一个整体来分析.UART驱动部分依赖于硬件平台,而TTY驱动和具体的平台无关. ...
- 7行代码解决P1441砝码称重(附优化过程)
先贴上最终代码感受一下: #include <bits/stdc++.h> using namespace std; int i, N, M, wi[21], res = 0; int m ...
- saltstack 服务器批量管理
学习saltstack 服务器批量管理 1.saltstack 简介 SaltStack是一个开源的.新的基础平台管理工具,使用Python语言开发,同时提供Rest API方便二次开发以及和其他运维 ...
- Kubernetes调整Node节点快速驱逐pod的时间
在高可用的k8s集群中,当Node节点挂掉,kubelet无法提供工作的时候,pod将会自动调度到其他的节点上去,而调度到节点上的时间需要我们慎重考量,因为它决定了生产的稳定性.可靠性,更快的迁移可以 ...
- Flink可靠性的基石-checkpoint机制详细解析
Checkpoint介绍 checkpoint机制是Flink可靠性的基石,可以保证Flink集群在某个算子因为某些原因(如 异常退出)出现故障时,能够将整个应用流图的状态恢复到故障之前的某一状态,保 ...
- Linux日志文件(常见)及其功能
日志文件是重要的系统信息文件,其中记录了许多重要的系统事件,包括用户的登录信息.系统的启动信息.系统的安全信息.邮件相关信息.各种服务相关信息等.这些信息有些非常敏感,所以在 Linux 中这些日志文 ...
- 提供一个HDFS内的文件的路径,对该文件进行创建和删除操作。如果文件所在目录不存在,则自动创建目录。
1 import java.text.SimpleDateFormat; 2 3 import org.apache.hadoop.fs.FSDataOutputStream; 4 import or ...
- 3.kafka安装配置
kafka安装配置 ### 1.集群规划 hadoop102 hadoop103 hadoop104 zk zk zk kafka kafka kafka jar包下载 http://kafka.ap ...
- AWS Lightsail 开启 Root 登陆权限
将下面代码中的第一句中的 Passwd 改为自己将要设置的密码,否则默认 root 密码为 Passwd. #!/bin/bash echo root:Passwd |sudo chpasswd ro ...
- Redis集群动态增加和删除节点
一.添加节点 1.首先将需要添加的节点启动: 这里启动redis6383.conf和redis6393.conf两个节点 查看原有节点: 3个主节点所对应的哈希槽(hash slo ...