【题解】P2839 [国家集训队] middle
0
首先我们要思考如何判断最大中位数是多少
即二分一个数 \(mid\),把 \(>=mid\) 的赋值为 \(1\) ,否则为 \(-1\) ,求最大区间值
如果 \(>=0\) ,则 \(mid\) 偏小,否则偏大,继续二分
1
对于如何快速求最大区间,最大前后缀
我们有一个想法,离散化,对于每一个权值 \(x\) 建立一颗线段树,这个线段树节点关于 \(x\) 赋值
然后维护线段树信息
但是暴力建树,时空都会爆炸,我们可以通过可持久化的方式优化时空
2:代码
#include<bits/stdc++.h>
#define inf 1e9
using namespace std;
const int N=2e4+10;
struct node{
int l,r;
int sum,maxl,maxr;
int son[2];
#define l(q) tree[q].l
#define r(q) tree[q].r
#define sum(q) tree[q].sum
#define maxl(q) tree[q].maxl
#define maxr(q) tree[q].maxr
#define ls(q) tree[q].son[0]
#define rs(q) tree[q].son[1]
void show(int q){
//cout<<"-->"<<q<<" "<<l<<" "<<r<<" "<<sum<<" "<<maxl<<" "<<maxr<<" "<<son[0]<<" "<<son[1]<<"\n";
}
void init(){
sum=0;
maxl=-inf;maxr=-inf;
}
}tree[N*25];int idx=0;
int root[N];
int id[N];
int a[N];
bool cmp(int x,int y){
return a[x]<a[y];
}
void push_up(int q){
sum(q)=sum(ls(q))+sum(rs(q));
maxl(q)=max(maxl(ls(q)),sum(ls(q))+maxl(rs(q)));
maxr(q)=max(maxr(rs(q)),sum(rs(q))+maxr(ls(q)));
}
node merge(node lx,node rx){
node c;
c.sum=lx.sum+rx.sum;
c.maxl=max(lx.maxl,lx.sum+rx.maxl);
c.maxr=max(rx.maxr,rx.sum+lx.maxr);
return c;
}
int build(int l,int r){
int q=++idx;
l(q)=l;r(q)=r;
sum(q)=maxl(q)=maxr(q)=r-l+1;
if(l==r) return q;
int mid=l+r>>1;
ls(q)=build(l,mid);
rs(q)=build(mid+1,r);
return q;
}
void update(int pre,int &now,int tp,int d){
now=++idx;
int q=now;
tree[q]=tree[pre];
int l=l(q),r=r(q);
if(l==r){
sum(q)=maxl(q)=maxr(q)=-1;
if(d==2) tree[q].show(q);
return ;
}
int mid=l+r>>1;
if(tp<=mid) update(ls(pre),ls(q),tp,d);
else update(rs(pre),rs(q),tp,d);
push_up(q);
if(d==2) tree[q].show(q);
}
node ans;
void query(int q,int L,int R){
int l=l(q),r=r(q);
if(L<=l&&r<=R){
//cout<<":";tree[q].show(q);
ans=merge(ans,tree[q]);
//cout<<l<<" "<<r<<" "<<ans.sum<<" "<<ans.maxl<<" "<<ans.maxr<<"\n";
//cout<<":";tree[q].show(q);
return ;
}
int mid=l+r>>1;
if(L<=mid) query(ls(q),L,R);
if(mid<R) query(rs(q),L,R);
//cout<<l<<" "<<r<<" "<<ans.sum<<" "<<ans.maxl<<" "<<ans.maxr<<"\n";
return ;
}
bool check(int x,int a,int b,int c,int d){
int res=0;
//cout<<x<<" ";
ans.init();query(root[x],a,b);res+=ans.maxr;//cout<<ans.maxr<<" ";
if(b+1<=c-1){
ans.init();
query(root[x],b+1,c-1);
res+=ans.sum;
//cout<<ans.sum<<" ";
}
ans.init();query(root[x],c,d);res+=ans.maxl;
///cout<<ans.maxl<<" ";
//cout<<res<<"\n";
return res>=0;
}
void dfs(int q){
tree[q].show(q);
int l=l(q),r=r(q);
if(l==r) return ;
dfs(ls(q));dfs(rs(q));
}
int main(){
int n;cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
id[i]=i;
}
sort(id,id+n,cmp);
root[0]=build(0,n-1);
for(int i=1;i<n;i++){
update(root[i-1],root[i],id[i-1],i);
}
//cout<<"----------->\n";
dfs(root[2]);
//cout<<"sigma";tree[3].show(3);
int m;cin>>m;
int ans=0;
while(m--){
int q[4];
for(int i=0;i<4;i++){
cin>>q[i];
q[i]=(q[i]+ans)%n;
}
sort(q,q+4);
//for(int i=0;i<4;i++) cout<<q[i]<<" ";cout<<"\n";
int l=0,r=n-1;
while(l<r){
int mid=l+r+1>>1;
if(check(mid,q[0],q[1],q[2],q[3])) l=mid;
else r=mid-1;
}
cout<<a[id[l]]<<"\n";
ans=a[id[l]];
}
///cout<<"sigma";tree[3].show(3);
//cout<<"----->\n";
//check(2,0,1,2,3);
return 0;
}
3:反思
3.1
最大中位数求解方式,可以先通过二分下手,转成判定问题
3.2
主席树也可以关于权值建立线段树

浙公网安备 33010602011771号