纪中暑假集训 2020.08.05【NOIP提高组】模拟 T2:【NOIP2015模拟11.5】Lucas的数列

【NOIP2015模拟11.5】Lucas的数列

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

5 5
1 2
2 3
3 4
4 5
5 6
1 2 4
1 3 0
1 5 3
1 5 2
5 5 0

Sample Output

1
empty
6
1
empty

Data Constraint

在这里插入图片描述

反思&题解

比赛思路: 模拟,可惜被精度卡掉了一分没拿
正解思路: 我们可以看到式子很恶心,所以精度问题会特别猥琐,所以我们不妨将式子化简得: K = m i = 1 m ( x i ) 2 ( i = 1 m x i ) 2 K=m\sum^m_{i=1}(xi)^2-(\sum^m_{i=1}xi)^2 ,所以其实K一直都是一个整数 (出题人你不善良) ,又因为问题没有强制在线,所以我们可以考虑离线的做法,我们将元素和询问分别按照w和z为关键字从小到大进行排序,那么对于每次询问只有它之前的元素有贡献,之后我们只需要一个支持单点修改和区间查询的结构就行了,类似线段树和树状数组(我用的是线段树)
反思: 突然又发现自己线段树掌握的不怎么样,这是个很万能的东西,一定要将其练习得了如指掌

CODE

#include<bits/stdc++.h>
using namespace std;
struct arr
{
	long long w,pos,num;
}a[400005];
struct huiyi
{
	long long x,y,z,num1;
}b[400005];
bool cmp1(arr x,arr y)
{
	return x.w<y.w;
}
bool cmp2(huiyi x,huiyi y)
{
	return x.z<y.z;
}
long long tree[1500005],treenum[1500005],treesqr[1500005],n,q,ans[400005],t1,t2,t3;
void change(long long now,long long l,long long r,long long p,long long k)
{
	if (l>p || r<p) return;
	if (l==r && l==p)
	{
		tree[now]=1;
		treenum[now]=k;
		treesqr[now]=k*k;
	}
	else
	{
		long long mid=l+r>>1;
		change(now<<1,l,mid,p,k);
		change(now<<1|1,mid+1,r,p,k);
		tree[now]=tree[now<<1]+tree[now<<1|1];
		treenum[now]=treenum[now<<1]+treenum[now<<1|1];
		treesqr[now]=treesqr[now<<1]+treesqr[now<<1|1];
	}
}
void find(long long now,long long l,long long r,long long x,long long y)
{
	if (l>y || r<x) return;
	if (tree[now]==0) return;
	if (l>=x && r<=y)
	{
		t1+=tree[now];
		t2+=treenum[now];
		t3+=treesqr[now];
	}
	else
	{
		long long mid=l+r>>1;
		find(now<<1,l,mid,x,y);
		find(now<<1|1,mid+1,r,x,y);
	}
}
int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	scanf("%lld%lld",&n,&q);
	long long i;
	for (i=1;i<=n;i++)
	{
		scanf("%lld%lld",&a[i].w,&a[i].pos);
		a[i].num=i;
	}
	for (i=1;i<=q;i++)
	{
		scanf("%lld%lld%lld",&b[i].x,&b[i].y,&b[i].z);
		b[i].num1=i;
	}
	sort(a+1,a+1+n,cmp1);
	sort(b+1,b+1+q,cmp2);
	long long j=1;
	for (i=1;i<=q;i++)
	{
		while (a[j].w<=b[i].z && j<=n)
		{
			change(1,1,n,a[j].num,a[j].pos);
			j++;
		}
		t1=0;
		t2=0;
		t3=0;
		find(1,1,n,b[i].x,b[i].y);
		if (t1==0) ans[b[i].num1]=-1;
		else ans[b[i].num1]=t1*t3-t2*t2;
	}
	for (i=1;i<=q;i++)
	{
		if (ans[i]==-1) printf("empty\n");
		else printf("%lld\n",ans[i]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/CMC_YXY/article/details/107830079