題目地址: http://poj.org/problem?id=3067
典型的樹狀數組題目。
跟小學時做的連線題很像,問共有多少個交點。兩點間只能用線段連,並且假設不會有3條及以上的線段交於同一點。
假設兩個點 (x1,y1)、(x2,y2)
假若 y2 > y1 ,那麼此時,只要存在 x1 < x2 ,那麼就一定存在交點。
即其中一點在另一點的左上方。
所以我們先對 y從大到小排序,若y相等則對x從大到小排序。
於是,對排序完成後的點集。從前往後遍曆。
每次遍曆:update(xi,1) ,橫座標為xi的數,數量加1 。 然後 query(xi - 1) ,其結果代表當前已記錄的、小於xi的橫座標總數,即得到該點左上方共有多少點。
簡單來說,就是用樹狀數組來hash得到某個範圍內的數的總數。而這個範圍內某些數的數量是不斷更新的。
#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int tree[10100];struct Point{int x,y;}p[1001000];int cmp(Point a,Point b){if(a.y==b.y) return a.x>b.x;return a.y>b.y;}int query(int x){int sum=0;while(x>0){sum+=tree[x];x-=x&-x;}return sum;}void update(int x,int n){while(x<=n){tree[x]++;x+=x&-x;}}int main(){int t,tt;int n,m,k;int sum,i;scanf("%d",&t);for(tt=1;tt<=t;tt++){scanf("%d%d%d",&n,&m,&k);for(i=1;i<=n;i++)tree[i]=0;sum=0;for(i=0;i<k;i++)scanf("%d%d",&p[i].x,&p[i].y);sort(p,p+k,cmp);for(i=0;i<k;i++){sum+=query(p[i].x-1);update(p[i].x,n);}printf("Test case %d: %d\n",tt,sum);}return 0;}