牛客练习赛108 C梦迹

 

题目大意:一个给定非负数组,每次操作替换其中一个数字,问替换后满足ai+aj<=w的数对有多少个(i<=j)?

先来个基础问题:一个数组中满足ai+aj<=w的数对有多少个? 一种方案:先排序+双指针遍历,如果a[1]最小(指针1),那么找到最大的a[i](指针2),使得a[1]+a[i]<=w,而a[1]+a[i+1]>w。那么显然a1能和这i个元素满足条件。然后两个指针同时后移即可。

本题目思路:注意题目给出数据范围ai一定小于300000。如果我们随意去除一个值为x的元素,那么会减少多少个满足条件的数对呢?显然这个值等于数组中小于等于w-x的元素个数。如果添加一个y进来,那么数组中所有小于等于w-y的元素都能和y凑成新数对。如何快速求出一个数组中小于某个值的元素个数,且数组中元素可变?

显然此问题是数据结构中经典的“树状数组”问题。具体过程见代码.

#include <iostream>
using namespace std;
int n,q,w,t[300005],a[300005];
long long all=0;
void add(int x,int v)
{
    for(;x<=300005;x+=x&(-x);)
        t[x]+=v;
}
int sum(int x)
{
    int s=0;
    for(; x>0; x-=x&(-x))
        s+=t[x];
    return s;
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i,j,p,x;/**< 树状数组不能解决0的问题,所以数据都加1处理,w则+2处理 */
    cin>>n>>q>>w;
    w+=2;
    for(i=1; i<=n; i++)
    {
        cin>>a[i],a[i]++,add(a[i],1);/**< 加入树状数组 */
        all+=sum(w-a[i]);/**< 求a[i]能凑成符合条件数对个数 */
    }
    while(q--)
    {
        cin>>p>>x;
        x++;
        all-=sum(w-a[p]);/**< 因为要把a[p]替换为x,所以先去除a[p]的数对 */
        add(a[p],-1);/**< 去除a[p] */
        a[p]=x;
        add(x,1);/**< 替换a[p]值为x,同时加入树状数组 */
        all+=sum(w-x);/**< 新增x带来的数对 */
        cout<<all<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值