Codeforces1539 F. Strange Array(思维,线段树)

题意:

在这里插入图片描述

解法:
考虑对于单组询问,查询x位置的答案.
考虑x在中值的左边,
那么选择的区间中,>=x的要尽量多,>=x的位置为1,<x的为-1,
维护一下前缀和,那么问题变为:在x的左右各选一个点l和r,
满足[l,r]的区间和最大.
因为到中值的距离=[(>=x的个数)-(<x的个数)]/2,
所以区间和最大一定最优.

用线段树维护前缀和的min和max,
在x的右边取一个max,左边取一个min,
相间就是最大区间和,用上面的式子计算出距离,更新答案即可.

那么多组询问怎么办?
将所有数从小到大排序,从左到右处理,
维护一个指针,每次将<当前数的位置变为-1即可,只需要线段树区间加法.
单次复杂度O(log),总复杂度O(n*log).

x在中值右边的情况,做法一致.
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxm=2e5+5;
struct Node{
    int v,id;
}e[maxm];
bool cmp(Node a,Node b){
    return a.v<b.v;
}
struct Tree{
    int laz[maxm<<2];
    int ma[maxm<<2];
    int mi[maxm<<2];
    inline void pp(int node){
        ma[node]=max(ma[node*2],ma[node*2+1]);
        mi[node]=min(mi[node*2],mi[node*2+1]);
    }
    inline void pd(int node){
        if(laz[node]){
            laz[node*2]+=laz[node];
            laz[node*2+1]+=laz[node];
            ma[node*2]+=laz[node];
            ma[node*2+1]+=laz[node];
            mi[node*2]+=laz[node];
            mi[node*2+1]+=laz[node];
            laz[node]=0;
        }
    }
    void update(int st,int ed,int val,int l,int r,int node){
        if(st<=l&&ed>=r){
            laz[node]+=val;
            ma[node]+=val;
            mi[node]+=val;
            return ;
        }
        pd(node);
        int mid=(l+r)/2;
        if(st<=mid)update(st,ed,val,l,mid,node*2);
        if(ed>mid)update(st,ed,val,mid+1,r,node*2+1);
        pp(node);
    }
    int ask_ma(int st,int ed,int l,int r,int node){
        if(st<=l&&ed>=r)return ma[node];
        pd(node);
        int mid=(l+r)/2;
        int ans=-1e9;
        if(st<=mid)ans=max(ans,ask_ma(st,ed,l,mid,node*2));
        if(ed>mid)ans=max(ans,ask_ma(st,ed,mid+1,r,node*2+1));
        return ans;
    }
    int ask_mi(int st,int ed,int l,int r,int node){
        if(st<=l&&ed>=r)return mi[node];
        pd(node);
        int mid=(l+r)/2;
        int ans=1e9;
        if(st<=mid)ans=min(ans,ask_mi(st,ed,l,mid,node*2));
        if(ed>mid)ans=min(ans,ask_mi(st,ed,mid+1,r,node*2+1));
        return ans;
    }
    void build(int l,int r,int node){
        ma[node]=mi[node]=laz[node]=0;
        if(l==r)return ;
        int mid=(l+r)/2;
        build(l,mid,node*2);
        build(mid+1,r,node*2+1);
    }
}T;
int ans[maxm];
int n;
void solve(){;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>e[i].v;e[i].id=i;
    }
    if(n==1){cout<<0<<endl;return ;}
    sort(e+1,e+1+n,cmp);
    T.build(1,n,1);
    for(int i=1;i<=n;i++){
        int id=e[i].id;
        T.update(id,n,1,1,n,1);
    }
    int j=1;
    for(int i=1;i<=n;i++){//x在中值左边
        while(e[j].v<e[i].v){//<当前数的设为-1
            int id=e[j].id;
            T.update(id,n,-2,1,n,1);
            j++;
        }
        int id=e[i].id;
        int len=0;
        if(id==1){
            len=T.ask_ma(id,n,1,n,1);
        }else{
            len=T.ask_ma(id,n,1,n,1)-min(0LL,T.ask_mi(1,id-1,1,n,1));
        }
        ans[id]=max(ans[id],len/2);
    }
    T.build(1,n,1);
    for(int i=1;i<=n;i++){
        int id=e[i].id;
        T.update(id,n,1,1,n,1);
    }
    j=n;
    for(int i=n;i>=1;i--){//x在中值右边
        while(e[j].v>e[i].v){
            int id=e[j].id;
            T.update(id,n,-2,1,n,1);
            j--;
        }
        int id=e[i].id;
        int len=0;
        if(id==1){
            len=T.ask_ma(id,n,1,n,1);
        }else{
            len=T.ask_ma(id,n,1,n,1)-min(0LL,T.ask_mi(1,id-1,1,n,1));
        }
        ans[id]=max(ans[id],(len+1)/2-1);//这里注意一下
    }
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<' ';
    }
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);
    solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值