LUOGU SP4226 MSE06H - Japan

P4226 MSE06H - Japan
題面(from luogu)
題目描述
English Vietnamese Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coast and M cities on the West coast (M

The funding for the construction is guaranteed by ACM. A major portion of the sum is determined by the number of crossings between superhighways. At most two superhighways cross at one location. Write a program that calculates the number of the crossings between superhighways.

輸入格式
The input file starts with T - the number of test cases. Each test case starts with three numbers – N, M, K. Each of the next K lines contains two numbers – the numbers of cities connected by the superhighway. The first one is the number of the city on the East coast and second one is the number of the city of the West coast.

輸出格式
For each test case write one line on the standard output:

Test case “case number”: “number of crossings”

題意翻譯
題目描述
日本計劃迎接ACM-ICPC世界總決賽,爲此必須修建大量道路。日本是一個高島,東海岸有N個城市,西海岸有M個城市(M <= 1000, N <= 1000)。將修建K條高速公路。每個海岸的城市編號分別是1、2、……從北到南。每條高速公路都是一條直線,連接着東海岸的城市和西海岸的城市。建設資金由ACM擔保。其中很大一部分是由高速公路之間的交叉點數量決定的。兩條高速公路最多在一個地點相交。編寫一個程序,計算高速公路之間的交叉點數量。

輸入輸出格式
輸入格式 輸入文件以T開頭代表測試用例的數量。每個測試用例都以三個數字開始(N, M, K),接下來的K行中每一行都包含兩個數字代表通過高速公路連接的城市數量。第一個是東海岸城市的數量第二個是西海岸城市的數量。

樣例輸入
1

3 4 4

1 4

2 3

3 2

3 1

樣例輸出
Test case 1: 5

輸入輸出樣例

題目分析
我們可以將題目中的公路理解成爲端點之間的線段
那麼根據題意,我們不難畫出如下的圖來(樣例)
在這裏插入圖片描述
根據上圖,很難不難發現規律,
如果兩條線段之間有着交點,那麼其在東邊或者是西邊的端點的大小總是相反的
我們可以將東邊的表示爲 x ,西邊的表示爲 y
那麼對於 xi , xj , yi , yj
則在:xi < xj 且 yi > yj 或者 xi > xj 且 yi < yj 時兩邊的線段存在交點
但是對於我們的求解,只需要其中一組情況即可
根據上述的規律,我們不難發現,其實在一側有序的前提下,交點的個數即使另一邊逆序對的個數
對於逆序對,我們可以使用樹狀數組來求解

但是這裏,有一個特別的地方需要我們注意到
對於來着同一個東邊端點的線段,我們在排序的時候需要特別注意到是要按從小到大來的,假設是從大到小話,就會生成多餘的逆序對

當然,這題的數據並不是很大,所以沒必要離散化了

代碼

#include <bits/stdc++.h>
using namespace std;

struct node{
	int x;
	int y;
}a[1000009];

int t[10009];
long long ans;
int n,m,k,T;
int j;
//樹狀數組的基本操作
int lowbit(int p) {   
	return p&(-p);
}

void add(int x) {
	for (int i = x; i <= m; i+=lowbit(i)) t[i]++; 
}

long long getsum(int x) {
	long long s = 0;
	for (int i = x; i > 0; i-=lowbit(i)) s += t[i];
	return s;
}

bool cmp(node X,node Y) {
	return (X.x < Y.x) || (X.x == Y.x && X.y < Y.y);   //要注意一下
}

int main() {
	scanf("%d",&T);
	while (T--) { j++;
		memset(t,0,sizeof(t));
		memset(a,0,sizeof(a));
		ans = 0;
	
		scanf("%d %d %d",&n,&m,&k);
		for (int i = 1; i <= k; i++) {
			scanf("%d %d",&a[i].x,&a[i].y);
		}
		sort(a+1,a+k+1,cmp);   //按東邊的排序
		
		for (int i = 1; i <= k; i++) add(a[i].y), ans += i - getsum(a[i].y);   //把當前元素加入樹狀數組,
												//	求逆序對的個數(用當前的總數字的個數減去順序對的個數)
		
		printf("Test case %d: %lld\n",j,ans);   //鬼畜的輸出
	}
	
	return 0;
}

crx CSP-J/S RP++

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章