1. 程式人生 > >Q - Castle Walls POJ - 1794 (求逆序對)

Q - Castle Walls POJ - 1794 (求逆序對)

Q - Castle Walls

 POJ - 1794 

Background 
In medieval times, knights commanded big armies of peasants. When they had to storm a castle they would line up neatly in front of the castle's wall and throw their grappling hooks over the walls. If one does not throw straight it can easily happen that two hooks cross, making it impossible for the two peasants to climb the wall. That's why every knight made his peasants practice a lot so that this would not happen in combat. 
Due to the recent Sir Arthur-Madam Claire Marriage (ACM), two peasant armies have to be merged. 
Traditionally Sir Arthur's peasants wear blue and Madame Claire's peasants wear red. When practicing together, both armies mix up in front of a castle's wall. On Sir Arthur's command, they all throw their grappling hooks. Due to their perfect training the hooks will never cross within an army, however it can happen that a hook thrown by a blue peasant crosses one thrown by a peasant of the red army. 
For statistical purposes, Sir Arthur now needs to find out how many grappling hooks have crossed so that he can measure how well their armies have already been merged. 
Problem 
Given the positions of blue and red peasants as well as the positions they threw their grappling hooks at,determine how many distinct pairs of blue and red peasants crossed their hooks. 
If there are n blue and m red peasants, the positions in the line where the peasants are standing are numbered from 1 to n + m. The positions on the castle's wall are numbered from 1 to n + m as well,where position i is directly opposite of position i on the line the peasants are standing on. A grappling hook thrown from position i to j is said to cross another hook thrown from k to l if and only if 
(i < k and j >= l) or (i > k and j <= l) 
Grappling hooks of the same color will never cross each other, nor will two peasants occupy the same position on the line. However, two hooks (of different color) can be thrown to the same position in which case they are said to cross each other as well.

Input

The first line contains the number of scenarios. 
In each scenario, you are first given a line with two integers n and m, the number of blue and red peasants, respectively (1 <= n,m <= 30 000). 
The next n lines describe the blue peasants followed by m more lines for the red peasants. Each line consists of two integer i and j separated by a space, indicating the peasant's position i and the position j he threw his grappling hook to (1 <= i, j <= n + m).

Output

For each scenario first output a line "Scenario #i:" where i is the number of the scenario starting with 1, followed by a line containing the number of distinct pairs of peasants whose grappling hooks are crossed,and print a blank line at the end of each scenario.

Sample Input

2
2 2
1 2
3 4
2 1
4 3
2 3
1 3
2 5
5 3
3 1
4 2

Sample Output

Scenario #1:
2

Scenario #2:
6

 每個農民戰士從x位置向y位置拋鉤子,如果y1(某隊的一個人拋的鉤子位置 )>y2(l另外一隊的一個人拋的鉤子位置)且x<=y2,則出現交叉,求這種交叉情況的數量,即逆序數。

思路:按照y升序,y相等,則x降序排序,排好序的陣列中,在y升序的情況下,當遍歷到第i個數對時,更新其出現在x位置的情況,用樹狀陣列直接對i位置節點及父節點加1,表示x位置出現過人,那麼x之前的沒有被更新過的x值情況,其對應的y值必定大於等於第i個數的y值。

#include<cstdio>
#include<stack>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<iostream>
#include<cmath>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int N=110;
const int nmax = 60200;
const double esp = 1e-9;
const double PI=3.1415926;
int n,m;
int c[nmax];
struct point
{
    int x,y;
} p[nmax];
int lowbit(int x){
return x&(-x);
}
void update(int k){
while(k<=n+m){
      c[k]+=1;
      k+=lowbit(k);
}
}
int query(int k){
      int ans=0;
while(k>0)
{
      ans+=c[k];
      k-=lowbit(k);
}
return ans;
}
bool cmp(point p1,point p2)  //y升序,y相等,則x降序
{
      if(p1.y==p2.y)
            return p1.x>p2.x;  //y相等時也是交叉的
      return p1.y<p2.y;
}
int main()
{
    int t,sum=0;
    scanf("%d",&t);
    while(t--)
    {
      scanf("%d%d",&n,&m);
      for(int i=0;i<n;i++)
            scanf("%d%d",&p[i].x,&p[i].y);
      for(int i=0;i<m;i++)
            scanf("%d%d",&p[i+n].x,&p[i+n].y);
      sort(p,p+m+n,cmp);
      memset(c,0,sizeof(c));
      int ans=0;
      for(int i=0;i<n+m;i++){
            update(p[i].x);  //更新出現在p[i].x的情況
            ans+=p[i].x-query(p[i].x); 
            /* query(p[i].x)為那些y值比p[i].y小且x比p[i].x小的總數量,那麼p[i].x-query(p[i].x)則表示x值比p[i].x小且y大於等於p[i].y的數量,即逆序對
            */
      }
      printf("Scenario #%d:\n",++sum);
      printf("%d\n\n",ans);
    }
    return 0;
}