poj1990 Moofest
阿新 • • 發佈:2020-09-12
題目連結:https://vjudge.net/problem/POJ-1990#author=0
題意:給定n個二元組(vi,xi),求Σmax(vi,vj)|xi-xj| (1<=i<j<=n)
首先按照v升序排序,這樣就不用考慮max(vi,vj)這一項。那麼對於每一個vi,它的貢獻為vi*Σ|xi-xj|(j<i)。把這個絕對值拆開計算,具體來說就是維護兩個樹狀陣列,一個維護i前面有多少個xj比它小,記為num;另外一個維護這些比它小的dj的和是多少記為s1,這樣就可以用vi*(xi*num-s1+s[i-1]-s1-(i-1-num)*xi)來計算,這兒s表示xi的字首和
#include<cstdio> #include<algorithm> #include<cstring> #define ll long long using namespace std; const int N=20000; struct st{ ll v,x;}a[N+10]; ll c[2][N+10],s[N+10],n,i,j,ans; bool cmp(st p,st q){return (p.v==q.v)?p.x<q.x:p.v<q.v;} void add(ll k,ll x,ll y){ for (ll i=x;i<=N;i+=i&-i) c[k][i]+=y; } ll ask(ll k,ll x){ ll res=0; for (ll i=x;i>0;i-=i&-i) res+=c[k][i]; return res; } int main(){ scanf("%lld",&n); for (i=1;i<=n;i++) scanf("%lld%lld",&a[i].v,&a[i].x); sort(a+1,a+n+1,cmp); memset(c,0,sizeof(c)); s[0]=0; ans=0; for (i=1;i<=n;i++) s[i]=s[i-1]+a[i].x; for (i=1;i<=n;i++){ ll num=ask(0,a[i].x); ll s1=ask(1,a[i].x); ans+=(a[i].v*(a[i].x*num-s1+s[i-1]-s1-(i-1-num)*a[i].x)); add(0,a[i].x,1); add(1,a[i].x,a[i].x); } printf("%lld\n",ans); return 0; }