[luogu]P2657低头一族[树状数组]

[luogu]P2657

低头一族

题目描述

一群青年人排成一队,用手机互相聊天。

每个人的手机有一个信号接收指标,第i个人的接收指标设为v[i]。

如果位置在x[i]的人要和位置在xj的人聊天,那么这两人组成的一对的信号发射强度就是abs(x[i]-x[j])*max(v[i],v[j]).

现在我们想知道,这些人所有对子中的信号发射强度的总和。

输入输出格式

输入格式:
第一行一个整数N,接下来N行,每行两个整数v[i]和x[i]。

输出格式:
所有对的信号发射强度总和。

输入输出样例

输入样例1#:
4
3 1
2 5
2 6
4 3
输出样例1#:
57
【说明】
对于40%的数据,N<=5,000
对于100%的数据,N<=100,000 1≤x[i]≤20,000
注意:可能有两人在同一个位置
答案在int64或long long范围内


 

两点间距*两点价值最大
考虑对答案贡献的是某一价值,那么就是要找寻比他小的。所以我们先按v进行排序。
考虑用树状数组统计答案。
用两个树状数组,一个记录(1...i)中的x坐标和,另一个是个数。
那么这个点对答案的贡献为:
v[i]*(getnum(x[i])*x[i]-getsum(x[i])+tot-getsum(x[i])-(i-getnum(x))*x[i])
tot每次累加x[i]。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long ll ;
 7 inline int read();
 8 namespace lys{
 9     const int N = 2e4 + 7 ;
10     struct LOW_head{
11         int v;
12         int x;
13     }a[100007];
14     ll bitS[N],bitN[N];
15     int lowbit(int x){return x&(-x);}
16     ll getS(int x){
17         ll res=0;
18         for(;x;x-=lowbit(x)) res+=bitS[x];
19         return res ;
20     }
21     ll getN(int x){
22         ll res=0;
23         for(;x;x-=lowbit(x)) res+=bitN[x];
24         return res ;
25     }
26     void insertS(int x,int y){for(;x<=N;x+=lowbit(x)) bitS[x]+=y;}
27     void insertN(int x){for(;x<=N;x+=lowbit(x)) bitN[x]++;}
28     bool cmp(const LOW_head &x,const LOW_head &y){return x.v<y.v;}
29     int n;
30     ll ans,tot;
31     int main(){
32         int i;
33         n=read();
34         for(i=0;i<n;i++) a[i].v=read(),a[i].x=read();
35         sort(a,a+n,cmp);
36         for(i=0;i<n;i++){
37             ans+=1LL*a[i].v*(1LL*(2*getN(a[i].x)-i)*a[i].x-2*getS(a[i].x)+tot);
38             tot+=a[i].x;
39             insertS(a[i].x,a[i].x);
40             insertN(a[i].x);
41         }
42         printf("%lld\n",ans);
43         return 0;
44     }
45 }
46 int main(){
47     lys::main();
48     return 0;
49 }
50 inline int read(){
51     int kk=0,ff=1;
52     char c=getchar();
53     while(c<'0'||c>'9'){
54         if(c=='-') ff=-1;
55         c=getchar();
56     }
57     while(c>='0'&&c<='9') kk=kk*10+c-'0',c=getchar();
58     return kk*ff;
59 }

 

转载于:https://www.cnblogs.com/Liisa/p/7928333.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值