题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3015
题意:给定n组数,每组数有值x和值h,求n组数两两的val的总和。将所有x和所有h分别离散化(不去重)变成x'和h',val(i,j)为abs(x'i-x'j)*min(hi',hj')。
如:
x, h——>x',h'
10,100——>1,1
50,500——>4,4
20,200——>3,3
20,100——>1,1
思路:只要把n*n优化成n*logn就可以过。
tip1:按照h'的值sort,并动态加点,每次加的点如果是已加点中h'最小的,那么min()中要取的值就为h'
tip2:离散化但是不去重,不需要unique
tip3:关于abs()部分的处理,两棵树状数组,一棵统计数量,一棵统计sum。abs()值为(大于x'的sum-大于x'的数量*x')+(小于x'的数量*x'-小于x'的sum)
tip4:res和sum树状数组均需要开long long
附上代码:
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int maxn=1e5+10; int C1[maxn],C2[maxn],n; int lowbit(int x) { return x&-x; } void add1(int x,int c) { for(;x<=n;x+=lowbit(x)) C1[x]+=c; } void add2(int x,int c) { for(;x<=n;x+=lowbit(x)) C2[x]+=c; } int query1(int x) { int res=0; for(;x;x-=lowbit(x)) res+=C1[x]; return res; }; long long query2(int x) { long long res=0; for(;x;x-=lowbit(x)) res+=C2[x]; return res; } struct node { int x,h; }p[maxn]; bool cmp(node a,node b) { if(a.h==b.h)return a.x>b.x; else return a.h>b.h; } int main() { while(scanf("%d",&n)!=EOF) { memset(C1,0,sizeof C1); memset(C2,0,sizeof C2); int x[maxn]={0},h[maxn]={0}; for(int i=0;i<n;i++)scanf("%d%d",&p[i].x,&p[i].h),x[i]=p[i].x,h[i]=p[i].h; sort(x,x+n); sort(h,h+n); sort(p,p+n,cmp); long long res=0; for(int i=0;i<n;i++) { int tmpx=lower_bound(x,x+n,p[i].x)-x+1; int tmph=lower_bound(h,h+n,p[i].h)-h+1; //cout<<tmpx<<" "<<tmph<<endl; res+=1ll*tmph*(-1ll*tmpx*(query1(n)-query1(tmpx))+1ll*tmpx*query1(tmpx-1)+query2(n)-query2(tmpx)-query2(tmpx-1)); add1(tmpx,1); add2(tmpx,tmpx); } printf("%lld\n",res); } return 0; }