POJ1990 (树状数组)

对于树状数组的理解不透+不会转化


题解:显然是要按照v排序的,那么首先在On情况下是可以完成max(vi,vj)的操作,对于某个牛i,我们只需考虑i之前的,那么i之前的牛我们需要知道每只牛j ,abs(dis(i) - dis(j)),去掉绝对值后,我们只需要知道所有dis(j) < dis(i)的牛的x的和 sum1,dis(j) > dis(i)的我们可以用总距离 - sum1 ,以及知道< dis(i) 的牛的个数num1,那么我们变可以用2个树状数组来分别维护了,
于是ans += ((num1 * x - sum1) + ( sum2 - sum1 - (i - num1) * x)))*v;
很巧妙啊


#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define fuck() (cout << " ------------------ " << endl)
const double eps = 1e-6;
const int maxn = 20000 + 5;
using namespace std;
struct node{
    int x,v;
    node(){}
    node(int x_, int v_):x(x_),v(v_){}
    bool operator < (const node & p) const {
        if(v == p.v)
            return x < p.x;
        return v < p.v;
    }
}cow[maxn];
LL sum[maxn];
LL num[maxn];
int lowbit(int x){
    return x & (-x);
}
void add(int x, int c, LL a[]){
    while(x <= maxn){
        a[x] += c;
        x += lowbit(x);
    }
}
LL getsum(int x, LL a[]){
    LL ans = 0;
    while(x){
        ans += a[x];
        x -= lowbit(x);
    }
    return ans;
}
int main(){
    int n;
    while(scanf("%d",&n) == 1){
        for(int i=0; i<n; i++)
            scanf("%d%d",&cow[i].v,&cow[i].x);
        sort(cow, cow+n);
        memset(sum, 0, sizeof(sum));
        memset(num, 0, sizeof(num));
        LL ans = 0;
        for(int i=0; i<n; i++){
            int x = cow[i].x;
            int v = cow[i].v;
            LL num1 = getsum(x,num);
            LL sum1 = getsum(x,sum);
            LL sum2 = getsum(maxn,sum);
            ans += (num1 * x - sum1 +      sum2 - sum1 - (i - num1) * x)*v;
            add(x,1,num);
            add(x,x,sum);
        }
        printf("%lld\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值