欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-10 20:25:38
...

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;
}

 

相关标签: 逆序对