51nod 1394 差和问题(算法马拉松8)

本文探讨了51nod算法马拉松中的一道题目——差和问题。通过对集合进行添加、删除元素的操作,并计算元素两两之间差的绝对值之和,展示了如何解决此类问题。在示例中,详细解释了每一步操作后集合的变化及其对应的差和计算,最终得出操作序列的结果。
摘要由CSDN通过智能技术生成

有一个集合S,初始状态下有n个元素,对他进行如下操作:

1、向S里面添加一个值为v的元素。输入格式为1 v

2、向S里面删除一个值为v的元素。输入格式为2 v

3、询问S里面的元素两两之差绝对值之和。输入格式为3

 

对于样例,

操作3,|1-2|+|1-3|+|2-3|=4

操作1 4之后,集合中的数字为1 2 3 4

操作3,|1-2|+|1-3|+|2-3|+|1-4|+|2-4|+|3-4|=10

操作2 2之后,集合中的数字为1 3 4

操作3,|1-3|+|1-4|+|3-4|=6


Input
第一行输入两个整数n,Q表示集合中初始元素个数和操作次数。(1<=n,Q<=100,000)
第二行给出n个整数a[0],a[1],a[2],…,a[n-1],表示初始集合中的元素。(0<=a[i]<=1,000,000,000) 
接下来Q行,每行一个操作。(0<=v<=1,000,000,000)
Output
对于第2类操作,如果集合中不存在值为v的元素可供删除,输出-1。
对于第3类操作,输出答案。
Input示例
3 5
1 2 3
3
1 4
3
2 2
3
Output示例
4
10
6

解题思路
离散化+树状数组,对每次1,2操作,用树状数组要统计比它大的个数和比它小的个数

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=200000+100;
struct node
{
    int id;
    long long v;
}q[maxn];
long long a[maxn*4];
int b[maxn*4];
long long t[maxn];
long long cur[maxn];
int cou[maxn];
long long low(int k)
{
    return k&(-k);
}
void update(int k,long long v,int v2)
{
    while(k<maxn)
    {
        a[k]+=v;
        b[k]+=v2;
        k+=low(k);
    }
}
long long anss,ansn;
long long sums(int k)
{
    anss=0,ansn=0;
    while(k>0)
    {
        anss+=a[k];
        ansn+=b[k];
        k-=low(k);
    }
}
int main()
{
    int n,qu;
    while(~scanf("%d%d",&n,&qu))
    {
        for(int i=0; i<n; i++)
        {
            scanf("%I64d",&t[i]);
            cur[i]=t[i];
        }
        int cnt=n;
        for(int i=0; i<qu; i++)
        {
            scanf("%d",&q[i].id);
            if(q[i].id!=3)
            {
                scanf("%I64d",&q[i].v);
                cur[cnt]=q[i].v;
                cnt++;
            }
        }
        sort(cur,cur+cnt);
        int all=unique(cur,cur+cnt)-cur;
        long long sum=0,ans=0;
        int sumn=0;
        int temp;
        for(int i=0;i<n;i++)
        {
            temp=lower_bound(cur,cur+all,t[i])-cur+1;
            cou[temp]++;
            sumn++;
            update(temp,t[i],1);
            sum+=t[i];
            sums(temp);
            ans=ans+(t[i]*(ansn*2-sumn)-2*anss+sum);
           // cout<<ans<<endl;
        }
        long long cwt;
        for(int i=0;i<qu;i++)
        {
            if(q[i].id==1)
            {
                //cout<<q[i].id<<"  "<<q[i].v<<endl;
                temp=lower_bound(cur,cur+all,q[i].v)-cur+1;
               // cout<<temp<<endl;
                update(temp,q[i].v,1);
                cou[temp]++;
                sum+=q[i].v;
                sumn++;
                sums(temp);
               // cout<<q[i].v*(ansn*2-sumn)-2*anss+sum<<endl;
               // cout<<anss<<"  "<<ansn<<"  "<<sum<<"  "<<q[i].v<<endl;
                ans=ans+(q[i].v*(ansn*2-sumn)-2*anss+sum);
               // cout<<ans<<endl;
            }
            else if(q[i].id==2)
            {
                temp=lower_bound(cur,cur+all,q[i].v)-cur+1;
                if(cou[temp]==0)
                {
                    printf("-1\n");
                }
                else
                {
                   sums(temp);
                   ans=ans-(q[i].v*(ansn*2-sumn)-2*anss+sum);
                  update(temp,-q[i].v,-1);
                  cou[temp]--;
                  sum-=q[i].v;
                  sumn--;
                }
            }
            else if(q[i].id==3)
            {
                printf("%I64d\n",ans);
            }
        }
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值