思路: 树状数组
分析:
1 题目给定n棵树的横坐标和高度,然后给定横坐标排序后的rank_f已及树的高度排序后的rank_s,规定两颗树的FAR为abs(rank_f[i] , rank_f[j]) , SHORT为min(rank_s[i] . rank[_sj]),那么i和j的组合的值为FAR*SHORT,求所有组合方式的总和
2 我们按照树的高度从大到小排序,然后我们分别求出每棵树的rank_f和rank_s , 然后我们就可以利用poj 1990
的思路去做
代码:
/*********************************************** * By: chenguolin * * Date: 2013-08-18 * * Address: http://blog.csdn.net/chenguolinblog * ***********************************************/ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef __int64 int64; const int MAXN = 1e5+10; struct Node{ int x; int h; int f; int s; bool operator<(const Node& s)const{ if(h > s.h) return true; else if(h == s.h && x > s.x) return true; return false; } }; Node node[MAXN]; int n , num[MAXN]; int64 treeNum[MAXN]; int64 treeRank[MAXN]; int lowbit(int x){ return x&(-x); } int64 getSum(int x , int64 *arr){ int64 sum = 0; while(x){ sum += arr[x]; x -= lowbit(x); } return sum; } void add(int x , int val , int64 *arr){ while(x < MAXN){ arr[x] += val; x += lowbit(x); } } void init(){ int s = 1; sort(num+1 , num+n+1); for(int i = n ; i > 0 ; i--){ if(i < n && node[i].h == node[i+1].h) node[i].s = node[i+1].s; else node[i].s = s; s++; node[i].f = lower_bound(num+1 , num+n+1 , node[i].x)-num; } } int64 solve(){ int64 ans = 0; sort(node+1 , node+n+1); init(); memset(treeNum , 0 , sizeof(treeNum)); memset(treeRank , 0 , sizeof(treeRank)); int64 total = 0; for(int i = 1 ; i <= n ; i++){ int64 f = node[i].f; int64 s = node[i].s; int64 count = getSum(f , treeNum); int64 sum = getSum(f , treeRank); ans += s*(count*f-sum); ans += s*(total-sum-(i-1-count)*f); add(f , 1 , treeNum); add(f , f , treeRank); total += f; } return ans; } int main(){ while(scanf("%d" , &n) != EOF){ for(int i = 1 ; i <= n ; i++){ scanf("%d%d" , &node[i].x , &node[i].h); num[i] = node[i].x; } printf("%I64d\n" , solve()); } return 0; }