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