51nod差和问题 1394

题意:

1394 差和问题
1.0 秒 131,072.0 KB 80 分 5级题
有一个多重集合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

输入
第一行输入两个整数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)
输出
对于第2类操作,如果集合中不存在值为v的元素可供删除,输出-1。
对于第3类操作,输出答案。
输入样例
3 5
1 2 3
3
1 4
3
2 2
3
输出样例
4
10
6

思路:

51nod,你绝了啊!!!!

首先,我们可以知道这是一道在线查询的题目

(1)插入 (2)删除 (3)查询 样样俱全

1.首先,我们先看看查询,查询的是绝对值。。。看似无从下手,但是排过序之后却是一目了然。假设当前a[i]有tnum个,比当前的数小的数的总和是tval,那么贡献就是tnum * a[i] - tval,比当前的数大的数的总和是tval,那么贡献就是tval - tnum * a[i]。

2.问题是我们排序了那么怎么完成插入和删除操作呢???
我们就先用一个结构体数组把操作信息存下来,要插入和删除的数就可以知道了。
可能当前有些数val是不存在的,那么可以用num[val] = 0表示

3.处理重复值问题,用一个num数组表示当前这个值val有多少个,当然0表示没有。map[val] = i表示val在i位置(map有时候很慢,少用!!!)

4.v的范围很大,但是n只有1e5,要离散化。。。

代码实现:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdlib>
#include<string>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const double pi = acos(-1.0);

int n,q;
ll a[maxn];//原始数组
struct node{//存储线段树的数组
	int l;
	int r;
	ll num;//统计数量
	ll val;//统计总和
}tree[maxn << 2];
int num[maxn];
map<ll,int>mp;

ll bin[maxn];//用于离散化的数组
ll ed;//离散化之后的长度

struct Query{//存查询的的结构体
	int id;
	ll x;
}qry[maxn/2];

ll tval,tnum;

void pushup(int k){
	tree[k].val = tree[k<<1].val + tree[k<<1|1].val;
	tree[k].num = tree[k<<1].num + tree[k<<1|1].num;
}

void build(int k,int l,int r){
	tree[k].l = l; tree[k].r = r;
	tree[k].num = tree[k].val = 0;
	if(l == r) return ;
	int mid = (l + r) >> 1;
	build(k << 1,l,mid);
	build(k<<1|1,mid + 1,r);
}

void update(int k,int i,ll v){
	if(tree[k].l == tree[k].r){
		tree[k].num += v;
		if(v == 1){
			tree[k].val += bin[i];
		}
		else tree[k].val -=  bin[i];
		return ;
	}
	int mid = (tree[k].l + tree[k].r)  >> 1;
	if(i <= mid) update(k<<1,i,v);
	else update(k<<1|1,i,v);
	pushup(k);
}


void query(int k,int l,int r){
	if(l > r){
		tnum = 0;
		tval = 0;
		return ;
	}
	//cout << k << ' ' << l << ' ' << r << endl;
	if(tree[k].l >= l&&tree[k].r <= r){
		tnum += tree[k].num;
		tval += tree[k].val;
		return ;
	}
	int mid = (tree[k].l + tree[k].r) >> 1;
	if(r <= mid) query(k << 1,l,r);
	else if(l > mid) query(k << 1|1,l,r);
	else{
		query(k << 1,l,r);
		query(k << 1|1,l,r);
	}
}

int main(){
	scanf("%d%d",&n,&q);//输入
	//cout << n  << ' ' << q << endl;

	memset(num,0,sizeof(num));//初始化
	mp.clear();
	
	int cnt = 0;
	for(int i = 1;i <= n;i++){//输入原始数组
		scanf("%lld",&a[i]);//原始数组
		bin[cnt++] = a[i];//用于离散化的数组
	}
	
	for(int i = 0;i < q;i++){//输入查询信息
		scanf("%d",&qry[i].id);
		if(qry[i].id == 1||qry[i].id == 2){
			scanf("%lld",&qry[i].x);
			bin[cnt++] = qry[i].x;
		}
	}

	sort(bin,bin + cnt);//离散化
	ed = unique(bin,bin + cnt) - bin;
	for(int i = 0;i < ed;i++){
		mp[bin[i]] = i; num[i] = 0;
		//cout  << bin[i] << ' ' << mp[bin[i]] << endl;
	}
	/*cout << cnt << endl;
	for(int i = 0;i < ed;i++)
		cout << bin[i] << ' ' ;
	cout << endl;*/

	build(1,0,ed);//建树
	//cout  << 1  << endl;

	ll ans = 0;
	//cout << ans << endl;
	for(int i = 1;i <= n;i++){
		update(1,mp[a[i]],1);
		//cout  << i << endl;
		tval = 0; tnum = 0;
		query(1,0,mp[a[i]] - 1);
	//	cout << i << endl;
		ans = ans + tnum * a[i] - tval;
		tval = 0; tnum = 0;
		query(1,mp[a[i]] + 1,ed - 1);
	//	cout << i << endl;
		ans = ans + tval - tnum * a[i];
		num[mp[a[i]]]++;
	//	cout << ans << endl;
	}
	//cout << ans << endl;
	for(int i = 0;i < q;i++){
		if(qry[i].id == 1){
			update(1,mp[qry[i].x],1);
			tval = 0; tnum = 0;
			query(1,0,mp[qry[i].x] - 1);
			ans = ans + tnum * qry[i].x - tval;
			tval = 0; tnum = 0;
			query(1,mp[qry[i].x] + 1,ed - 1);
			ans = ans + tval - tnum * qry[i].x;
			num[mp[qry[i].x]]++;
		}
		else if(qry[i].id == 2){
			if(num[mp[qry[i].x]] == 0){
				printf("-1\n");
				continue;
			}
			update(1,mp[qry[i].x],-1);
			tval = 0; tnum = 0;
			query(1,0,mp[qry[i].x] - 1);
			ans = ans -( tnum * qry[i].x - tval);
			tval = 0; tnum = 0;
			query(1,mp[qry[i].x] + 1,ed - 1);
			ans = ans -( tval - tnum * qry[i].x);
			num[mp[qry[i].x]]--;
		}
		else{
			printf("%lld\n",ans);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值