P4513
题意:
给
n
个
元
素
,
带
单
点
修
改
操
作
,
每
次
询
问
区
间
内
长
度
至
少
为
1
的
给n个元素,带单点修改操作,每次询问区间内长度至少为1的
给n个元素,带单点修改操作,每次询问区间内长度至少为1的
最
大
连
续
子
段
和
是
多
少
?
最大连续子段和是多少?
最大连续子段和是多少?
思路:
与
U
V
a
3938
类
似
与UVa3938 类似
与UVa3938类似
用
线
段
树
维
护
,
把
区
间
当
成
节
点
,
维
护
这
个
节
点
的
(
长
度
至
少
为
1
的
以
下
均
省
略
)
用线段树维护,把区间当成节点,维护这个节点的(长度至少为1的以下均省略)
用线段树维护,把区间当成节点,维护这个节点的(长度至少为1的以下均省略)
最
大
前
缀
和
、
最
大
后
缀
、
区
间
和
、
区
间
最
大
连
续
子
段
和
最大前缀和、最大后缀、区间和、区间最大连续子段和
最大前缀和、最大后缀、区间和、区间最大连续子段和
设
为
m
x
s
u
b
、
m
x
s
u
f
、
s
u
m
、
a
n
s
设为mxsub、mxsuf、sum、ans
设为mxsub、mxsuf、sum、ans
对
于
一
个
节
点
的
最
大
前
缀
和
:
要
么
为
左
子
节
点
的
m
x
s
u
b
,
要
么
为
左
子
节
点
的
s
u
m
+
右
子
节
点
的
m
x
s
u
b
对于一个节点的最大前缀和:要么为左子节点的mxsub,要么为左子节点的sum+右子节点的mxsub
对于一个节点的最大前缀和:要么为左子节点的mxsub,要么为左子节点的sum+右子节点的mxsub
对
于
一
个
节
点
的
最
大
后
缀
和
:
要
么
为
右
子
节
点
的
m
x
s
u
f
,
要
么
为
右
子
节
点
的
s
u
m
+
左
子
节
点
的
m
x
s
u
b
对于一个节点的最大后缀和:要么为右子节点的mxsuf,要么为右子节点的sum+左子节点的mxsub
对于一个节点的最大后缀和:要么为右子节点的mxsuf,要么为右子节点的sum+左子节点的mxsub
对
于
一
个
节
点
的
最
大
连
续
区
间
和
要
么
为
左
子
节
点
的
a
n
s
,
要
么
为
右
子
节
点
的
a
n
s
,
要
么
为
左
的
m
x
s
u
f
+
右
的
m
x
s
u
b
对于一个节点的最大连续区间和要么为左子节点的ans,要么为右子节点的ans,要么为左 的mxsuf + 右的mxsub
对于一个节点的最大连续区间和要么为左子节点的ans,要么为右子节点的ans,要么为左的mxsuf+右的mxsub
还
有
一
个
坑
点
:
询
问
的
区
间
不
一
定
L
<
=
R
,
Q
A
Q
还有一个坑点:询问的区间不一定L <= R,QAQ
还有一个坑点:询问的区间不一定L<=R,QAQ
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 5e5+10;
int n,m;
ll a[N];
struct Node{
int l,r;
//该节点的最大前缀,该节点的最大后缀,区间和,该节点的最大连续区间和
ll mx_sub,mx_suf,sum,ans;
}tr[N<<2];
void pushup(Node& root,Node& ls,Node& rs){
root.sum = ls.sum + rs.sum;
root.mx_sub = max(ls.mx_sub,ls.sum+rs.mx_sub);
root.mx_suf = max(rs.mx_suf,rs.sum + ls.mx_suf);
root.ans = max(max(ls.ans,rs.ans),ls.mx_suf+rs.mx_sub);
}
void build(int p,int l,int r){
tr[p].l = l,tr[p].r = r;
if(l == r){
tr[p].mx_sub = tr[p].mx_suf = tr[p].ans = tr[p].sum = a[l];
return;
}
int mid = l + r >> 1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(tr[p],tr[p<<1],tr[p<<1|1]);
}
//单点修改,把 a[x] 修改为 y.
void update(int p,int x,int y){
if(tr[p].l == tr[p].r){
tr[p].sum = tr[p].ans = tr[p].mx_sub = tr[p].mx_suf = y;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
if(x <= mid) update(p<<1,x,y);
else update(p<<1|1,x,y);
pushup(tr[p],tr[p<<1],tr[p<<1|1]);
}
//询问[L,R]的最大连续子段和
Node query(int p,int L,int R){
int l = tr[p].l,r = tr[p].r;
if(l >= L&&R >= r) return tr[p];
int mid = l + r >> 1;
if(R <= mid) return query(p<<1,L,R);
else if(L > mid) return query(p<<1|1,L,R);
else{
Node ls = query(p<<1,L,R);
Node rs = query(p<<1|1,L,R);
Node res;
pushup(res,ls,rs);
return res;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++) scanf("%lld",a+i);
build(1,1,n);
while(m--){
int op;scanf("%d",&op);
if(op == 1){
int l,r;scanf("%d%d",&l,&r);
if(l > r) swap(l,r);
printf("%lld\n",query(1,l,r).ans);
}else{
int x,y;scanf("%d%d",&x,&y);
update(1,x,y);
}
}
return 0;
}
P2824
题意:
给
出
一
个
1
到
n
的
排
列
,
然
后
每
次
进
行
一
次
局
部
排
列
,
可
能
升
序
排
,
可
能
降
序
排
给出一个1到n的排列,然后每次进行一次局部排列,可能升序排,可能降序排
给出一个1到n的排列,然后每次进行一次局部排列,可能升序排,可能降序排
最
后
来
一
个
询
问
,
问
位
置
p
是
什
么
数
字
最后来一个询问,问位置p是什么数字
最后来一个询问,问位置p是什么数字
思路:
这
题
的
二
分
想
法
太
女
少
了
这题的二分想法太女少了
这题的二分想法太女少了
对
于
c
h
e
c
k
一
个
x
,
对
于
一
个
原
来
排
列
相
较
于
x
变
成
一
个
01
串
,
大
于
等
于
x
为
1
,
小
于
x
为
0
对于check一个x,对于一个原来排列相较于x变成一个01串,大于等于x为1,小于x为0
对于check一个x,对于一个原来排列相较于x变成一个01串,大于等于x为1,小于x为0
例
如
:
a
i
:
1
例如:a_i : 1
例如:ai:1
4
4
4
2
2
2
3
3
3
5
5
5,
相
较
与
3
变
成
:
b
i
:
0
相较与3变成:b_i:0
相较与3变成:bi:0
1
1
1
0
0
0
1
1
1
1
1
1 ;
然
后
局
部
排
序
就
是
询
问
该
区
间
有
多
少
个
1
,
如
果
升
序
就
把
后
面
的
全
修
改
为
1
,
降
序
则
将
前
面
修
改
然后局部排序就是询问该区间有多少个1,如果升序就把后面的全修改为1,降序则将前面修改
然后局部排序就是询问该区间有多少个1,如果升序就把后面的全修改为1,降序则将前面修改
全
部
局
部
排
序
完
成
后
,
检
查
p
位
置
是
1
还
是
0
全部局部排序完成后,检查p位置是1还是0
全部局部排序完成后,检查p位置是1还是0
这
个
有
啥
用
?
这个有啥用?
这个有啥用?
因
为
相
较
于
x
将
其
变
成
01
串
再
去
局
部
排
序
完
毕
后
,
不
影
响
p
位
置
这
个
值
与
x
的
相
对
大
小
因为相较于x将其变成01串再去局部排序完毕后,不影响p位置这个值与x的相对大小
因为相较于x将其变成01串再去局部排序完毕后,不影响p位置这个值与x的相对大小
换
句
话
讲
,
如
果
p
位
置
是
1
,
那
么
按
正
常
局
部
排
序
后
a
p
是
满
足
a
p
>
=
x
的
换句话讲,如果p位置是1,那么按正常局部排序后a_p是满足a_p >= x的
换句话讲,如果p位置是1,那么按正常局部排序后ap是满足ap>=x的
既
然
这
样
我
们
一
直
二
分
找
到
最
大
的
x
既然这样我们一直二分找到最大的x
既然这样我们一直二分找到最大的x
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 1e5+10;
int n,m,q,a[N];
int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
return f*x;
}
struct Node{
int l,r,lazy,sum;
}tr[N<<2];
//操作类型、操作区间
struct node{
int opt,l,r;
}op[N];
void pushup(int p){
tr[p].sum = tr[p<<1].sum + tr[p<<1|1].sum;
}
void build(int p,int l,int r){
tr[p].lazy = -1,tr[p].sum = 0;
tr[p].l = l,tr[p].r = r;
if(l == r) return;
int mid = l + r >> 1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void pushdown(int p){
if(tr[p].lazy != -1){
tr[p<<1].lazy = tr[p<<1|1].lazy = tr[p].lazy;
tr[p<<1].sum = (tr[p<<1].r - tr[p<<1].l + 1)*tr[p].lazy;
tr[p<<1|1].sum = (tr[p<<1|1].r - tr[p<<1|1].l + 1)*tr[p].lazy;
tr[p].lazy = -1;
}
}
void update(int p,int L,int R,int dx){
if(L > R) return;
int l = tr[p].l,r = tr[p].r;
if(l >= L&&r <= R){
tr[p].lazy = dx;
tr[p].sum = (r - l + 1)*dx;
return;
}
pushdown(p);
int mid = l + r >> 1;
if(L <= mid) update(p<<1,L,R,dx);
if(R > mid) update(p<<1|1,L,R,dx);
pushup(p);
}
int query(int p,int L,int R){
int l = tr[p].l,r = tr[p].r;
if(l >= L&& r <= R) return tr[p].sum;
pushdown(p);
int mid = l + r >> 1;
int ans = 0;
if(L <= mid) ans += query(p<<1,L,R);
if(R > mid) ans += query(p<<1|1,L,R);
return ans;
}
bool check(int x){
build(1,1,n);
//将数组变成01串
for(int i = 1;i <= n;i++){
update(1,i,i,(a[i]>=x));
}
//局部排序操作
for(int i = 1;i <= m;i++){
int opt = op[i].opt,L = op[i].l,R = op[i].r;
int cnt = query(1,L,R);//这个区间1的个数
//升序就把0全部放前面,1全部放到后面
//降序就把1全部放前面,0全部放后面
if(opt == 0){
update(1,R - cnt + 1,R,1);
update(1,L,R - cnt,0);
}else{
update(1,L,L + cnt - 1,1);
update(1,L + cnt,R,0);
}
}
return query(1,q,q) == 1;
}
int main(){
n = read();m = read();
for(int i = 1;i <= n;i++){
a[i] = read();
}
for(int i = 1;i <= m;i++){
op[i].opt = read();op[i].l = read();op[i].r = read();
}
int l = 1,r = n;
q = read();
int ans = -1;
while(l <= r){
int mid = l + r >> 1;
if(check(mid)){
ans = mid;
l = mid + 1;
}else r = mid - 1;
}
printf("%d\n",ans);
return 0;
}