2020-10-13

莫队简单入门题(二)


https://vjudge.net/problem/CodeForces-86D

An array of positive integers a1, a2, …, an is given. Let us consider its arbitrary subarray al, al + 1…, ar, where 1 ≤ l ≤ r ≤ n. For every positive integer s denote by Ks the number of occurrences of s into the subarray. We call the power of the subarray the sum of products Ks·Ks·s for every positive integer s. The sum contains only finite number of nonzero summands as the number of different values in the array is indeed finite.
You should calculate the power of t given subarrays.
Input
First line contains two integers n and t (1 ≤ n, t ≤ 200000) — the array length and the number of queries correspondingly.
Second line contains n positive integers ai (1 ≤ ai ≤ 106) — the elements of the array.
Next t lines contain two positive integers l, r (1 ≤ l ≤ r ≤ n) each — the indices of the left and the right ends of the corresponding subarray.
Output
Output t lines, the i-th line of the output should contain single positive integer — the power of the i-th query subarray.
Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preferred to use cout stream (also you may use %I64d).
Examples
Input
3 2
1 2 1
1 2
1 3
Output
3
6
Input
8 3
1 1 2 2 1 3 1 1
2 7
1 6
2 7
Output
20
20
20
题意:就是每种数字x对答案的贡献是(xx出现次数),求总贡献

#include<iostream>
#include<algorithm> 
#include<cmath>
#include<cstring> 
#define ll long long
using namespace std;
const int maxn=1000006;
int n,m,k,a[maxn],b[maxn],book[maxn];
ll cnt[maxn],ans[maxn],sum;
struct fun
{
	int l;
	int r;
	int id;
}mo[maxn];
void add(int pos)
{
	sum+=((2*cnt[a[pos]]+1)*a[pos]);
	cnt[a[pos]]++;

}
void del(int pos)
{
	cnt[a[pos]]--;
	sum-=((2*cnt[a[pos]]+1)*a[pos]);
	
}
bool cmp(fun x,fun y)
{
	return b[x.l]<b[y.l]||(b[x.l]==b[y.l]&&(b[x.l]&1?x.r<y.r:x.r>y.r));
//	if(b[x.l]==b[y.l ])
//	return x.r<y.r;
//	else return x.l<y.l ;
}
int main()
{
	scanf("%d%d",&n,&m);
	int size=sqrt(n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		b[i]=i/size+1;
	}
	for(int i=0;i<m;i++)
	{
		scanf("%d%d",&mo[i].l ,&mo[i].r );
		mo[i].id=i;
	}
	sort(mo,mo+m,cmp);
	int l=1,r=0;
	for(int i=0;i<m;i++)
	{
		while(l>mo[i].l)
		{
			add(l-1);
			l--;
		}
		while(l<mo[i].l )
		{
			del(l);
			l++;
		}
		while(r>mo[i].r)
		{
			del(r);
			r--;
		}
		while(r<mo[i].r )
		{
			add(r+1);
			r++;
		}
		ans[mo[i].id]=sum;
	}
	for(int i=0;i<m;i++)
	{
		printf("%lld\n",ans[i]);
	 } 
}

很容易能算出,x²和 (x+1)²差值是2K+1,很容易就能套入add函数,del函数里面了。
也就是个模板题,但是我为什么TLE那么多次!!!居然是因为忘记对分块进行排序了o(╥﹏╥)o==可能是因为写的时候思绪太飘了。。。。。。这都能忘,唉

不过,这个莫队玄学奇偶性排序,确实比原来的(见下代码注释)要快那么一些。。。4116ms和4648ms,以后还是用这个排序方法吧!!

bool cmp(fun x,fun y)
{
	return b[x.l]<b[y.l]||(b[x.l]==b[y.l]&&(b[x.l]&1?x.r<y.r:x.r>y.r));
//	if(b[x.l]==b[y.l ])
//	return x.r<y.r;
//	else return x.l<y.l ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这是一个 SQL 语句,用于向借阅表中插入数据。该表包含以下字段:借阅编号、读者编号、书籍编号、借阅日期、归还日期、借阅状态。每条数据表示一次借阅记录。其中借阅编号、读者编号、书籍编号、借阅日期和借阅状态是必填项,归还日期为可选项,如果借阅状态为“已还”则必须填写归还日期。 具体插入的数据如下: - 借阅编号:100001,读者编号:123413,书籍编号:0001,借阅日期:2020-11-05,归还日期:NULL,借阅状态:借阅 - 借阅编号:100002,读者编号:223411,书籍编号:0002,借阅日期:2020-9-28,归还日期:2020-10-13,借阅状态:已还 - 借阅编号:100003,读者编号:321123,书籍编号:1001,借阅日期:2020-7-01,归还日期:NULL,借阅状态:过期 - 借阅编号:100004,读者编号:321124,书籍编号:2001,借阅日期:2020-10-09,归还日期:2020-10-14,借阅状态:已还 - 借阅编号:100005,读者编号:321124,书籍编号:0001,借阅日期:2020-10-15,归还日期:NULL,借阅状态:借阅 - 借阅编号:100006,读者编号:223411,书籍编号:2001,借阅日期:2020-10-16,归还日期:NULL,借阅状态:借阅 - 借阅编号:100007,读者编号:411111,书籍编号:1002,借阅日期:2020-9-01,归还日期:2020-9-24,借阅状态:已还 - 借阅编号:100008,读者编号:411111,书籍编号:0001,借阅日期:2020-9-25,归还日期:NULL,借阅状态:借阅 - 借阅编号:100009,读者编号:411111,书籍编号:1001,借阅日期:2020-10-08,归还日期:NULL,借阅状态:借阅

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值