The 2023 ICPC Asia Shenyang Regional Contest K. Maximum Rating
K.Maximum Rating
题意简述
给定一个长为 \(n\) 的序列,通过重排操作后,记从 1到 i 的前缀和为 \(pre_i\),判断通过重排能产生多少可能的值 $ \sum_{j=1}^n [pre_j > \max_{i=1}^{j-1} pre_i]$.
解题思路
注意到:
1.可能的最大值就是正数的个数。
2.可能的最小值是把正数从小到大往后排,负数全插最前面去到的。
3.贪心的把负数看成一个集合,正数从大到小排列,然后把负数集合从后往前插入每个位置,这样可以得到最大值和最小值中间每一种数字。
4.所以答案就是询问正数的个数减去不可以被负数绝对值之和抵消的正数的个数
把正数和负数分开,
对于每个查询就是快速询问小于等于负数绝对值和的正数前缀的最大位置是多少?
单点修,区间查,考虑离散化后建一棵权值树状数组 or 权值线段树,每次二分找出一个合法的位置
时间复杂度 \(\mathcal{O}(n \log n \log n)\)
AC code(线段树)
//Stop learning useless algorithms, go and solve some problems, learn how to use binary search.
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
#define lc (p<<1)
#define rc (p<<1|1)
#define dbg(...) cout<<"usedchang"<<endl
const int N=4e5+2;
int n,m;
namespace Seg{
    struct node{
        int l,r;
        ll sum,add;
        ll num,laz;
    }tree[N<<2];
    void pushup(int p){
        tree[p].sum=tree[lc].sum+tree[rc].sum;
        tree[p].num=tree[lc].num+tree[rc].num;
    }
    void pushdown(int p){
        if(tree[p].add==0) return;
        tree[lc].sum+=1LL*(tree[lc].r-tree[lc].l+1)*tree[p].add;
        tree[lc].num+=1LL*(tree[lc].r-tree[lc].l+1)*tree[p].laz;
        tree[lc].add+=tree[p].add;
        tree[rc].sum+=1LL*(tree[rc].r-tree[rc].l+1)*tree[p].add;
        tree[rc].num+=1LL*(tree[rc].r-tree[rc].l+1)*tree[p].laz;
        tree[rc].add+=tree[p].add;
        tree[p].add=tree[p].laz=0;
    }
    void build(int l=1,int r=n+m+1,int p=1){
        int mid=l+r>>1;
        tree[p]={l,r,0,0,0,0};
        if(l==r) return;
        build(l,mid,lc);
        build(mid+1,r,rc);
        pushup(p);
    }
    void upd(int x,int y,ll k,int w=1,int p=1){
        if(x<=tree[p].l&&y>=tree[p].r){
            tree[p].sum+=1LL*k*(tree[p].r-tree[p].l+1);
            tree[p].add+=k;
            tree[p].num+=1LL*w*(tree[p].r-tree[p].l+1);
            tree[p].laz+=w;
            return;
        }
        int mid=tree[p].l+tree[p].r>>1;
        pushdown(p);
        if(x<=mid) upd(x,y,k,w,lc);
        if(y>mid) upd(x,y,k,w,rc);
        pushup(p);
    }
    ll qry(int x,int y,int p=1){
        if(x>y) return 0;
        if(x<=tree[p].l&&y>=tree[p].r){
            return tree[p].sum;
        }
        pushdown(p);
        ll ans=0;
        int mid=tree[p].l+tree[p].r>>1;
        if(x<=mid) ans+=qry(x,y,lc);
        if(y>mid) ans+=qry(x,y,rc);
        return ans;
    }
    int asknums(int x,int y,int p=1){
        if(x>y) return 0;
        if(x<=tree[p].l&&y>=tree[p].r){
            return tree[p].num;
        }
        pushdown(p);
        int ans=0;
        int mid=tree[p].l+tree[p].r>>1;
        if(x<=mid) ans+=asknums(x,y,lc);
        if(y>mid) ans+=asknums(x,y,rc);
        return ans;
    }
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    cin>>n>>m;
    Seg::build();
    vector<int>a(n),b;
    ll sum=0;
    for(int i=0;i<n;i++) {
        cin>>a[i];
        b.emplace_back(a[i]);
    }
    vector< pair<int,int> >q(m);
    for(int i=0;i<m;i++){
        int x,k;
        cin>>x>>k;
        --x;
        q[i]={x,k};
        b.emplace_back(k);
    }
    auto c=b;
    sort(b.begin(),b.end());
    auto Idx=[&](int k){
        return lower_bound(b.begin(),b.end(),k)-b.begin()+1;
    };
    for(auto &x:a) {
        if(x<0) sum+=-x;
        Seg::upd(Idx(x),Idx(x),x);
    }
    for(auto &[x,y]:q){
        int Old=Idx(a[x]);
        Seg::upd(Old,Old,-a[x],-1);
        if(a[x]<0) sum-=-a[x];
        a[x]=y;
        int New=Idx(a[x]);
        Seg::upd(New,New,a[x],1);
        if(a[x]<0) sum+=-a[x];
        int st=Idx(1),ed=b.size();
        int l=st,r=ed;
        if(l>r){
            cout<<1<<endl;
            continue;
        }
        while(l<=r){
            int mid=l+r>>1;
            if(Seg::qry(st,mid)<=sum) l=mid+1;
            else r=mid-1;
        }
        ll ans=Seg::asknums(st,l-1)+1;
        ll rem=sum-Seg::qry(st,l-1);
        ll k=(l<b.size()&&b[l]>0)?rem/b[l]:0;
        cout<<ans+k<<endl;
    }
    return 0;
}
AC code(树状数组)
//Stop learning useless algorithms, go and solve some problems, learn how to use binary search.
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
#define lc (p<<1)
#define rc (p<<1|1)
#define dbg(...) cout<<"usedchang"<<endl
const int N=4e5+2;
int n,m;
struct BIT{
    vector<ll>a;
    int n;
    BIT(int _n){
        n=_n+1;
        a.resize(n+1); 
    }
    void add(int x,ll k){
        while(x<=n){
            a[x]+=k;
            x+=(x&-x);
        }
    }
    ll qry(int x){
        ll ans=0;
        while(x){
            ans+=a[x];
            x&=x-1;
        }
        return ans;
    }
    ll qry(int l,int r){
        return qry(r)-qry(l-1);
    }
};
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    cin>>n>>m;
    vector<BIT>tre(2,BIT(n+m+1));
    vector<int>a(n),b;
    ll sum=0;
    for(int i=0;i<n;i++) {
        cin>>a[i];
        b.emplace_back(a[i]);
    }
    vector< pair<int,int> >q(m);
    for(int i=0;i<m;i++){
        int x,k;
        cin>>x>>k;
        --x;
        q[i]={x,k};
        b.emplace_back(k);
    }
    auto c=b;
    sort(b.begin(),b.end());
    auto Idx=[&](int k){
        return lower_bound(b.begin(),b.end(),k)-b.begin()+1;
    };
    for(auto &x:a) {
        if(x<0) sum+=-x;
        tre[0].add(Idx(x),x);
        tre[1].add(Idx(x),1);
    }
    for(auto &[x,y]:q){
        int Old=Idx(a[x]);
        tre[0].add(Old,-a[x]);
        tre[1].add(Old,-1);
        if(a[x]<0) sum-=-a[x];
        a[x]=y;
        int New=Idx(a[x]);
        tre[0].add(New,a[x]);
        tre[1].add(New,1);
        if(a[x]<0) sum+=-a[x];
        int st=Idx(1),ed=b.size();
        int l=st,r=ed;
        if(l>r){
            cout<<1<<endl;
            continue;
        }
        while(l<=r){
            int mid=l+r>>1;
            if(tre[0].qry(st,mid)<=sum) l=mid+1;
            else r=mid-1;
        }
        ll ans=tre[1].qry(st,l-1)+1;
        ll rem=sum-tre[0].qry(st,l-1);
        ll k=(l<b.size()&&b[l]>0)?rem/b[l]:0;
        cout<<ans+k<<endl;
    }
    return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号