POJ1990:MooFest——题解

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

题目大意:定义一对在树轴上的点,每对点产生的值为两点权值最大值*两点距离,求点对值和。

显然n*n复杂度不行,我们需要用树状数组维护两个东西。

对于某位置,一个是它和它前置位坐标和,一个是它和它前置位点的个数。

我们按照点i权值v从小到大排序添加,这样对于我们在树状数组里的点,我们一定是要乘当前的点的v,剩下的就是乘距离了。

对于坐标比它小的点的个数为num,坐标和为x,我们有答案num*x[i]-x。

同理对于坐标比它大的点也可以求,化简得到:

ans+=c[i].v*(querydis(N)-2*querydis(c[i].x)-(i-1-2*querynum(c[i].x))*c[i].x);

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll read(){
    int X=0,w=0; char ch=0;
    while(ch<'0'||ch>'9'){w|=ch=='-';ch=getchar();}
    while(ch>='0'&&ch<='9')X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
const int N=20001;
struct cow{
    int v;
    int x;
}c[N];
bool cmp(cow a,cow b){
    return a.v<b.v;
}
int n,m;
ll num[N],dis[N];
inline int lowbit(int t){return t&(-t);}
void add(int x,int y1,int y2){
    for(int i=x;i<=N;i+=lowbit(i)){num[i]+=y1;dis[i]+=y2;}
    return;
}
ll querydis(int x){
    ll res=0;
    for(int i=x;i>0;i-=lowbit(i))res+=dis[i];
    return res;
}
ll querynum(int x){
    ll res=0;
    for(int i=x;i>0;i-=lowbit(i))res+=num[i];
    return res;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
    c[i].v=read();
    c[i].x=read();
    }
    sort(c+1,c+n+1,cmp);
    ll ans=0;
    for(int i=1;i<=n;i++){
    ans+=c[i].v*(querydis(N)-2*querydis(c[i].x)-(i-1-2*querynum(c[i].x))*c[i].x);
    add(c[i].x,1,c[i].x);
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2017-11-23 20:34  luyouqi233  阅读(225)  评论(0编辑  收藏  举报