/*
作者也不会做
网上找了份代码 Ctrl+C 了下来
再用 Ctrl+V 大法就过了
还请谅解
另:(也是网上抄的)
线段树太垃圾了
大神们可以用平衡树求前驱后继来求 le 和 ri (即左区间(left)和右区间(right))
*/
#include<bits/stdc++.h>
#define N 200005
using namespace std;
int le[4*N],ri[4*N],f[4*N],cnt[4*N],h[N],n;
//线段树求解左区间
void pushdown_l(int k){
if (le[k]==0) return;
le[k<<1]=max(le[k<<1],le[k]);
le[k<<1|1]=max(le[k<<1|1],le[k]);
}
void add_l(int k,int l,int r,int L,int R,int v){
if (r<L||R<l) return;
if (L<=l&&r<=R){
le[k]=max(le[k],v);
return;
}
pushdown_l(k);
int mid=l+r>>1;
add_l(k<<1,l,mid,L,R,v);
add_l(k<<1|1,mid+1,r,L,R,v);
}
int get_l(int k,int l,int r,int p){
if (l==r){
return le[k];
}
pushdown_l(k);
int mid=l+r>>1;
if (p<=mid) return get_l(k<<1,l,mid,p); else return get_l(k<<1|1,mid+1,r,p);
}
//线段树求解右区间
void pushdown_r(int k){
if (ri[k]==n+1) return;
ri[k<<1]=min(ri[k<<1],ri[k]);
ri[k<<1|1]=min(ri[k<<1|1],ri[k]);
}
void add_r(int k,int l,int r,int L,int R,int v){
if (r<L||R<l) return;
if (L<=l&&r<=R){
ri[k]=min(ri[k],v);
return;
}
pushdown_r(k);
int mid=l+r>>1;
add_r(k<<1,l,mid,L,R,v);
add_r(k<<1|1,mid+1,r,L,R,v);
}
int get_r(int k,int l,int r,int p){
if (l==r){
return ri[k];
}
pushdown_r(k);
int mid=l+r>>1;
if (p<=mid) return get_r(k<<1,l,mid,p); else return get_r(k<<1|1,mid+1,r,p);
}
//用线段树标记不同的 Bessie 值(即 f 数组)( 1 表示 HI,0 表示 LO,2 表示下辖区块可能 HI,也可能 LO)
void build(int k,int l,int r){
if (l==r){
f[k]=2;
h[l]=k;//为方便输出,用 h 数组记得 l 的节点值为 k
return;
}
int mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
f[k]=2;
}
//更新 k 节点的值为 v
void count(int k,int v){
if (v==2) return;
if (f[k]==1&&v==0){
f[k]=v;
cnt[k]++;
} else f[k]=v;
}
// f 上放
void pushup(int k){
if (f[k<<1]==2||f[k<<1|1]==2){
f[k]=2;
} else if (f[k<<1]!=f[k<<1|1]){
f[k]=2;
} else if (f[k<<1]==f[k<<1|1]){
f[k]=f[k<<1];
f[k<<1]=f[k<<1|1]=2;//当子节点值相同时,防止重复计算,子节点赋值为不确定
}
}
// f 、懒标记下放
void pushdown(int k){
count(k<<1,f[k]);
cnt[k<<1]+=cnt[k];
count(k<<1|1,f[k]);
cnt[k<<1|1]+=cnt[k];
cnt[k]=0;
}
//更改区间值为 v
void change(int k,int l,int r,int L,int R,int v){
if (r<L||R<l) return;
if (L<=l&&r<=R){
count(k,v);
return;
}
pushdown(k);
int mid=l+r>>1;
change(k<<1,l,mid,L,R,v);
change(k<<1|1,mid+1,r,L,R,v);
pushup(k);
}
//将所有 f 、懒标记的值下放
void query(int k,int l,int r){
if (l==r) return;
pushdown(k);
int mid=l+r>>1;
query(k<<1,l,mid);
query(k<<1|1,mid+1,r);
}
int main(){
scanf("%d",&n);
//左右区间初始化
for (int i=1;i<=4*n;i++) {
le[i]=0;
ri[i]=n+1;
}
build(1,0,n);//构造线段树
for (int i=1;i<=n;i++){
int p;
scanf("%d",&p);
int x=get_l(1,1,n,p),y=get_r(1,1,n,p);//取出每个值对应的左右区间
change(1,0,n,x,p-1,1);//对于 left ~ p 标记 HI
change(1,0,n,p,y-1,0);//对于 p ~ right 标记 LO
add_l(1,1,n,p+1,n,p);//把 p 加入 p 右边的左区间计算中
add_r(1,1,n,1,p-1,p);//把 p 加入 p 左边的右区间计算中
}
query(1,0,n);//把所有懒标记下方
//输出
for (int i=0;i<=n;i++)
printf("%d\n",cnt[h[i]]);
return 0;
}
不会做P905 HILO怎么办
2023-06-04 21:08:35 By syxx_tangchenhui
评论
caxx_shaozenan
膜
- 2023-06-05 19:42:12
dfdf_xuziye
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- 2023-09-12 18:44:56