题解:CF1990F Polygonal Segments
LastKismet · · 题解
能组成非退化多边形的条件是二倍最大值小于总和,对于同一个位置作为最大值区间越长是越不劣的。那么一个显然的做法是建出笛卡尔树,若当前点符合条件就返回,否则递归入儿子。一个性质是每次区间和都会减半,深度是
考虑上线段树。我们对区间维护笛卡尔树,特别地对上文符合条件的点可以只保留他自己、删除其子树内其他元素,因为其他元素及其区间在各方面均不优于该合法点。合并信息类似 FHQ-Treap,可持久化一下,由深度性质知单次复杂度
const int N=2e5+5;
int n,q;
ll a[N];
int tot;struct node{ll dat,sum,SUM;int len,LEN,ls,rs,ans;}ns[N*40];
il int nnode(ll v){++tot;ns[tot].dat=ns[tot].sum=ns[tot].SUM=v,ns[tot].ans=-1,ns[tot].len=ns[tot].LEN=1,ns[tot].ls=ns[tot].rs=0;return tot;}
il int cnode(int x){ns[++tot]=ns[x];return tot;}
il int upd(int x){
ns[x].SUM=ns[ns[x].ls].SUM+ns[x].sum+ns[ns[x].rs].SUM;
ns[x].LEN=ns[ns[x].ls].LEN+ns[x].len+ns[ns[x].rs].LEN;
ns[x].ans=ns[x].ls||ns[x].rs?max(ns[ns[x].ls].ans,ns[ns[x].rs].ans):ns[x].len;
return x;
}
il int merge(int x,int y){
if(!x||!y)return x|y;
if(ns[x].dat>ns[y].dat){
x=cnode(x);
if(ns[x].dat*2<ns[x].SUM+ns[y].SUM)return ns[x].sum=ns[x].SUM+ns[y].SUM,ns[x].len=ns[x].LEN+ns[y].LEN,ns[x].ls=ns[x].rs=0,upd(x);
return ns[x].rs=merge(ns[x].rs,y),upd(x);
}else{
y=cnode(y);
if(ns[y].dat*2<ns[x].SUM+ns[y].SUM)return ns[y].sum=ns[x].SUM+ns[y].SUM,ns[y].len=ns[x].LEN+ns[y].LEN,ns[y].ls=ns[y].rs=0,upd(y);
return ns[y].ls=merge(x,ns[y].ls),upd(y);
}
}
int dat[N<<2];
void build(int x=1,int l=1,int r=n){
if(l==r)return dat[x]=nnode(a[l]),void();
int m=l+r>>1;build(x<<1,l,m),build(x<<1|1,m+1,r);
dat[x]=merge(dat[x<<1],dat[x<<1|1]);
}
void modify(int k,ll v,int x=1,int l=1,int r=n){
if(l==r)return dat[x]=nnode(v),void();
int m=l+r>>1;k<=m?modify(k,v,x<<1,l,m):modify(k,v,x<<1|1,m+1,r);
dat[x]=merge(dat[x<<1],dat[x<<1|1]);
}
int query(int lq,int rq,int x=1,int l=1,int r=n){
if(lq<=l&&r<=rq)return dat[x];
int m=l+r>>1;
if(rq<=m)return query(lq,rq,x<<1,l,m);
if(m<lq)return query(lq,rq,x<<1|1,m+1,r);
return merge(query(lq,rq,x<<1,l,m),query(lq,rq,x<<1|1,m+1,r));
}
void INIT(){ns[0].ans=-1;}
void MAIN(){
tot=0;
read(n,q);
rep(i,1,n)read(a[i]);
build();
rep(i,1,q){
ll op,x,y;read(op,x,y);
if(op==1)put(ns[query(x,y)].ans);
else modify(x,y);
}
}