[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 }