POJ 1990 MooFest(树状数组好题)

题目链接:

http://poj.org/problem?id=1990

题意:

给定 n n n个奶牛,每个奶牛有两个权值,第一个 p o s pos pos表示位置,每个点的 p o s pos pos均不相同,第二个表示 v a l val val表示奶牛声音传播属性,对于两个奶牛 ( x , y ) (x,y) (xy)之间的交流有一个结果,值等于 ∣ p o s x − p o s y ∣ \left| pos_x-pos_y\right| posxposy ∗ \ast m a x ( v a l x , v a l y ) max(val_x,val_y) max(valx,valy),求 ( n − 1 ) n 2 \frac{(n-1)n}{2} 2(n1)n对奶牛相互交流得到的这个结果的和;

分析:

       我们首先将奶牛按 v a l val val排序,那么对于奶牛 x x x,(下面说的之前并不是指距离,而是指按 v a l val val排序过后的相对位置);它之前的奶牛 y y y与它交流的 m a x ( v a l x , v a l y ) max(val_x,val_y) max(valx,valy)均等于 v a l x val_x valx,这时候我们对于每个奶牛 x x x,只需要计算它与它之前奶牛的距离 p o s pos pos的绝对值的和即可,那么如何计算 ∣ p o s x − p o s y ∣ \left| pos_x-pos_y\right| posxposy呢;
       对于每个奶牛 x x x之前的奶牛 y y y x x x的距离有两种可能,要么 p o s x > p o s y pos_x>pos_y posx>posy,要么 p o s x < p o s y pos_x<pos_y posx<posy;我们用 d i s > dis_> dis>代表位于 x x x之前的满足 p o s x < p o s y pos_x<pos_y posx<posy的所有 p o s y pos_y posy和即( ∑ p o s y \sum pos_y posy),同样有 d i s < dis_< dis<代表位于 x x x之前的满足 p o s x > p o s y pos_x>pos_y posx>posy的所有 p o s y pos_y posy和即( ∑ p o s y \sum pos_y posy),又有 n u m > num_> num>,代表 p o s x > p o s y pos_x>pos_y posx>posy y y y的个数,有 n u m < num_< num<,代表 p o s x < p o s y pos_x<pos_y posx<posy y y y的个数,那么有对于每个奶牛只要计算 ∑ i = 1 n v a l i ∗ ( n u m < ∗ p o s x − d i s < + d i s > − n u m > ∗ p o s x ) \sum_{i=1}^n val_i\ast(num_<\ast pos_x-dis_<+dis_>-num_>\ast pos_x) i=1nvali(num<posxdis<+dis>num>posx),这就是我们需要的答案, n u m num num d i s dis dis用两个树状数组求即可;

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define  inf 0x7f7f7f7f
#define  maxn 16041
#define  N 2
#define mod 100003

typedef long long ll;
typedef struct {
    int u, v, next, w;
} Edge;
Edge e[N];
int cnt, head[N];

inline void add(int u, int v) {
    e[cnt].u = u;
    e[cnt].v = v;
    //e[cnt].w=w;
    // e[cnt].f=f;
    e[cnt].next = head[u];
    head[u] = cnt++;
    //e[cnt].u=v;
//    e[cnt].v=u;
//    e[cnt].w=0;
//    e[cnt].f=-f;
//    e[cnt].next=head[v];
//    head[v]=cnt++;
}

inline void write(int x) {
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
struct cow {
    ll pos, val;
};

bool compare(cow a, cow b) {
    return a.val < b.val;
}

cow c[22000];
ll maxm,n, dis[20200], cot[20200];

void insert(ll x, ll t[], ll val) {
    while (x <= 20040) {
        t[x] += val;
        x += x & -x;
    }
}

ll sum(ll x,ll t[]){
    ll res=0;
    while(x){
        res+=t[x];
        x-=x&-x;
    }
    return res;
}
int main() {
    while (cin >> n) {
        memset(dis,0,sizeof(dis));
        memset(cot,0,sizeof(cot));
        for (int i = 1; i <= n; i++) {
            scanf("%lld%lld", &c[i].val, &c[i].pos);
        }
        sort(c + 1, c + 1 + n, compare);
        ll ans = 0;
        ll did=0,dix=0,nud=0,nux=0;
        for (int i = 1; i <= n; i++) {
            dix=sum(c[i].pos,dis);
            did=sum(20040,dis)-dix;
            nux=sum(c[i].pos,cot);
            nud=sum(20040,cot)-nux;
            insert(c[i].pos,cot,1);
            insert(c[i].pos,dis,c[i].pos);
            ans+=c[i].val*(nux*c[i].pos-dix);
            ans+=c[i].val*(did-nud*c[i].pos);
        }
        cout<<ans<<endl;
    }
    return 0;
}

我们坚持一件事情,并不是因为这样做了会有效果,而是坚信,这样做是对的。
——哈维尔

你可能感兴趣的:(POJ 1990 MooFest(树状数组好题))