【树状数组】ybtoj1741 电子速度

本文介绍了一种使用三个树状数组记录和更新电子速度的方法,实现对电子速度的修改及区间内电子飘升系数的快速查询,适用于大规模数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1741:电子速度


时间限制: 4000 ms         内存限制: 524288 KB
 

【题目描述】

选取显像管的任意一个平面,一开始平面内有n个电子,初始速度分别为vi ,定义飘升系数为:\sum_{1\leq i<j\leq n}|\overrightarrow{v_{i}}*\overrightarrow{v_{j}}|

电子的速度常常会发生变化。也就是说,有两种类型的操作:

•1pxy将 改为 (x,y);

•2lr询问[l,r]这段区间内的电子的飘升系数。

答案对20170927取模即可。

【输入】

第一行两个整数n,m,表示电子个数和询次个数。

接下来n行, 每行两个整数 x,y表示 vi。

接下来m行, 每行形如1 p x y或 2 l r,分别表示两种操作。

【输出】

对于每个操作2,输出一行一个整数表示飘升系数对 20170927 取模的值。

【输入样例】

9 5
13052925 5757314
9968857 11135327
13860145 3869873
6912189 3461377
2911603 7061332
6334922 7708411
5505379 5915686
6806727 588727
7603043 15687404
2 1 6
1 7 2602783 18398476
1 8 8636316 19923037
2 2 7
2 2 4

【输出样例】

18529202
963126
19167545

【提示】

【数据规模与约定】

测试点编号nm
1≤100≤100
2≤500≤500
3≤1000≤1000
4≤5000≤5000
5≤10000≤10000
6≤50000≤50000
7≤100000≤100000
8≤500000≤500000
9≤1000000≤1000000
10≤1000000≤1000000

对于100%的数据,1≤n,m≤10^6,0≤xi,yi<20170927,1≤li≤ri≤n。

\sum_{1\leq i<j\leq n}(x_{i}y_{j}-x_{j}y_{i})^2\\=\sum_{1\leq i<j\leq n}(x_{i}y_{j})^2+\sum_{1\leq i<j\leq n}(x_{j}y_{i})^2-2\sum_{1\leq i<j\leq n}(x_{j}x_{i}y_{i}y_{j})\\=\frac{1}{2}sum_{1\leq i,j\leq n}x_{i}^2y_{j}^2+\frac{1}{2}\sum_{1\leq i,j\leq n}x_{j}^2y_{i}^2-\sum_{1\leq i,j\leq n}(x_{i}y_{i}*x_{j}y_{j})\\=\sum_{1\leq i\leq n}x_{i}^2+\sum_{1\leq i\leq n}y_{i}^2-\sum_{1\leq i\leq n}(x_{i}y_{i})^2

 

然后就可以构造三个树状数组去记录着三个值即可

 

 

代码

#include<bits/stdc++.h>
#pragma GCC optimize(3)
using namespace std;
const int maxn=1e6+5;
const int mod=20170927;
int x[maxn],y[maxn],n,m;
long long a[maxn],b[maxn],c[maxn];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int lb(int x)
{
	return x&-x;
}
void add(int pos,long long x,long long y)
{
	for(;pos<=n;pos+=lb(pos))
	{
		a[pos]=(a[pos]+(x*x)%mod+mod)%mod;
		b[pos]=(b[pos]+(y*y)%mod+mod)%mod;
		c[pos]=(c[pos]+(x*y)%mod+mod)%mod;
	}
}
void del(int pos,long long x,long long y)
{
	for(;pos<=n;pos+=lb(pos))
	{
		a[pos]=(a[pos]-(x*x)%mod+mod)%mod;
		b[pos]=(b[pos]-(y*y)%mod+mod)%mod;
		c[pos]=(c[pos]-(x*y)%mod+mod)%mod;
	}
}
long long calca(int pos)
{
	long long res=0;
	for(;pos;pos-=lb(pos)) res=(res+a[pos])%mod;
	return res;
}
long long calcb(int pos)
{
	long long res=0;
	for(;pos;pos-=lb(pos)) res=(res+b[pos])%mod;
	return res;
}
long long calcc(int pos)
{
	long long res=0;
	for(;pos;pos-=lb(pos)) res=(res+c[pos])%mod;
	return res;
}
long long querya(int l,int r)
{
	return (calca(r)-calca(l-1)+mod)%mod;
}
long long queryb(int l,int r)
{
	return (calcb(r)-calcb(l-1)+mod)%mod;
}
long long queryc(int l,int r)
{
	return (calcc(r)-calcc(l-1)+mod)%mod;
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout); 
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) 
	{	
		x[i]=read(); y[i]=read();
		add(i,x[i],y[i]);
	}
	int aa,bb,cc;
	for(int i=1;i<=m;i++)
	{
		int op=read();
		if(op==1)
		{
			aa=read(); bb=read(); cc=read();
			del(aa,x[aa],y[aa]);
			add(aa,bb,cc);
			x[aa]=bb; y[aa]=cc;
		}
		if(op==2)
		{
			aa=read(); bb=read();
			long long res=querya(aa,bb)*queryb(aa,bb)%mod;
			long long ress=queryc(aa,bb);
			res=(res-ress*ress%mod+mod)%mod;
			printf("%lld\n",res);
		}
	}
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值