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;
}