题目描述
链接:https://vjudge.net/problem/POJ-1990
题目有点难读,但我就是想偷个懒~
思路分析
这道题有点像求逆序数的那道题。
首先,因为它要的两个因素(max(val)和abs(dis))里,和顺序有关的主要是max(val),那么我们就想到对它按照val进行排序:保证现在加入树中的元素的val最大。之后,就和逆序数的思路一样,加入一个,然后通过树状数组计算出两边的位置和,和目前这个牛的位置处理一下出来距离和,然后就能得到关于这头牛的max(val)*abs(dis)。
通过这两道题加深了对树状数组的理解:其实他就是个维护数据的结构,我们可以做的操作就是单点修改的区间求和,我们就把它当作存取数据的东西就行了,不用考虑过多。
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
#define lowbit(x) ((x)&-(x))
const int maxn=20005;
typedef long long ll;
struct cow{
int v;//价值
int i;//距离
bool operator<(cow n){
if(v==n.v){
return i<n.i;
}
return v<n.v;
}
};
ll tree1[maxn];//存数量 以距离为键
ll tree2[maxn];//存距离 以距离为键
cow data[maxn];
int n;
void add1(ll x,ll num){//对tree1操作
while(x<maxn){
tree1[x]+=num;
x+=lowbit(x);
}
}
void add2(ll x,ll num){//对tree2操作,下同
while(x<maxn){
tree2[x]+=num;
x+=lowbit(x);
}
}
ll sum1(ll x){
ll ans=0;
while(x>0){
ans+=tree1[x];
x-=lowbit(x);
}
return ans;
}
ll sum2(int x){
ll ans=0;
while(x>0){
ans+=tree2[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d %d",&data[i].v,&data[i].i);
}
sort(data,data+n);//按照val升序排序
ll ans=0;
for(int i=0;i<n;i++){
int v=data[i].v;//因为按照val的升序排序,所以当前的val肯定是最大的
int d=data[i].i;
ll numl=sum1(d-1);//左边牛的数量
ll numr=sum1(maxn)-sum1(d);//右边牛的数量
ll dsl=sum2(d-1);
ll ds2=sum2(maxn)-sum2(d);
ans+=v*(d*numl-dsl+ds2-d*numr);
add1(d,1);
add2(d,d);
}
printf("%lld\n",ans);
return 0;
}