「比赛报告」P7

「比赛报告」P7

来源:校模拟赛。

T1

ez

T2

ez

T3

ez

T4

题目

有一个 \(n\) 个数的序列 \(A\) ,定义 \(f(A)=\left|\{\min\limits_{i=0}^x(\sum\limits_{j=0}^i{A_j})\:|\:x\in[1,n]\}\right|\:\:\:(A_0=0)\)

\(m\) 次修改操作,每次修改会将 \(A_x\) 修改为 \(y\) 。定义 \(P\)\(A\) 的任意一种排列,在每次修改后输出所有 \(P\) 中不同 \(f(P)\) 的个数。

\(2\leq n,m\leq 2\times 10^5\:,\: 1\leq x\leq n \:,\:-10^9\leq y,A_i\leq 10^9\)

思路

显然可以通过将正数都放前面来使得 \(f(P)\) 最大,通过将 \(P\) 从小到大排序使得 \(f(P)\) 最小。

可以证明最大值和最小值之间的数都可以被构造出来。

\(f(P)\) 的最大值为 \(r\) ,最小值为 \(l\)

\(r=\left|\{A_i\:|A_i>0\wedge i\in[1,n]\}\right|\) 。记 \(x\)\(A\) 从小到大排序后第一个前缀和大于 \(0\) 的位置,\(l=n-x\)

现在瓶颈是计算 \(l\) 的复杂度为 \(\mathcal{O(n\log n)}\)

考虑值域线段树上二分。

我们在值域线段树上维护所有 \(A_i>0\)\(A_i\) 。记 \(sum\) 为所有负数的和。

也就是说我们只需要在线段树上找到第一个位置 \(pos\) ,使得所有\(\leq pos\) 的数加起来 \(\geq-sum\) 即可。

复杂度 \(\mathcal{O(n\log V+m\log V)}\)\(V\) 为值域。

注意

  1. 值域比较大,建议离线下来离散化一下。

  2. 注意有相同数的情况。

#include<bits/stdc++.h>
using namespace std;
const long long MX=200010,INF=1e9;
struct node{
    long long lc,rc;
    long long sum,siz;
}tree[20000010];
long long root,cnt;
inline void  update(long long now){
    tree[now].sum=tree[tree[now].lc].sum+tree[tree[now].rc].sum;
    tree[now].siz=tree[tree[now].lc].siz+tree[tree[now].rc].siz;
}
void add(long long &now,long long lt,long long rt,long long pos,long long val){
    if(lt>pos||rt<pos)  return ;
    if(!now)  now=++cnt;
    if(lt==rt){  tree[now].sum+=val;tree[now].siz+=val>0?1:-1;return ;}
    long long mid=(lt+rt-1)>>1;
    add(tree[now].lc,lt,mid,pos,val),add(tree[now].rc,mid+1,rt,pos,val);
    return update(now);
}
void cy(long long now,long long lt,long long rt,long long val,long long &pos){
    if(lt==rt){  pos=lt;return ;}
    long long mid=(lt+rt-1)>>1;
    if(tree[tree[now].lc].sum<val)  cy(tree[now].rc,mid+1,rt,val-tree[tree[now].lc].sum,pos);
    else  cy(tree[now].lc,lt,mid,val,pos);
}
long long query(long long now,long long lt,long long rt,long long l,long long r){
    if(rt<l||lt>r)    return 0;
    if(l<=lt&&rt<=r)  return tree[now].siz;
    long long mid=(lt+rt-1)>>1;
    return query(tree[now].lc,lt,mid,l,r)+query(tree[now].rc,mid+1,rt,l,r);
}
long long query_(long long now,long long lt,long long rt,long long l,long long r){
    if(rt<l||lt>r)    return 0;
    if(l<=lt&&rt<=r)  return tree[now].sum;
    long long mid=(lt+rt-1)>>1;
    return query_(tree[now].lc,lt,mid,l,r)+query_(tree[now].rc,mid+1,rt,l,r);
}
long long input[MX]={0};
signed main(){
    long long n,m;scanf("%lld%lld",&n,&m);
    long long sum=0,sx=0;bool flag=1;
    for(long long i=1;i<=n;i++){  scanf("%lld",&input[i]),sum+=input[i]<=0,sx+=input[i]*(input[i]<=0),flag&=input[i]>0;if(input[i]>0)  add(root,0,INF,input[i],input[i]);}
    while(m--){
        long long x,y;scanf("%lld%lld",&x,&y);flag&=y>0;
        if(y<=0)  sum++,sx+=y;
        else  add(root,0,INF,y,y);
        if(input[x]<=0)  sum--,sx-=input[x];
        else  add(root,0,INF,input[x],-input[x]);
        if(flag){puts("1");continue;}
        input[x]=y;
        long long pox=0;cy(root,0,INF,-sx,pox);
        long long minn=query(root,0,INF,0,pox-1),maxn=n-sum;
        minn+=min((-sx-query_(root,0,INF,0,pox-1))/pox,query(root,0,INF,pox,pox));
        minn=n-sum-minn;
        printf("%lld\n",maxn-minn+1);
    }
    return 0;
}
posted @ 2024-10-18 16:38  是菜菜呀  阅读(24)  评论(0编辑  收藏  举报