1. 程式人生 > 其它 >E. Correct Placement(思維)

E. Correct Placement(思維)

題目:E. Correct Placement

題目連結:https://codeforces.com/contest/1472/problem/E

題意:有n(1 <= n <= 2e5)個人,每個人有h(高度)、w(寬度)兩個值。這n個人要拍照片。對於一個人i,如果存在一個人j(j不等於i)滿足wi > wj && hi > wj或 wi > hj && hi > wj,那麼j就要排在i的前面。對於每個人i,求出任意的一個j。

輸入:第一行輸入測試用例個數t。

t 個測試用例。每個測試用例第一行是人數n。接下來n行,每行輸入第i個人的高度hi和寬度wi(1 <= hi, wi <= 1e9)。

輸出:對於每個i,輸出任意的一個j,若不存在j,則輸出 -1。

樣例輸入:

1

3

3 4

5 4

3 3

樣例輸出:

-1 3 -1

樣例解釋:

對於第一個人,因為h1 < h2 && h1 == h3,所以輸出-1。

對於第二個人,因為h2 > w2 && w2 > h1,所以可以輸出3。

對於第三個人,因為h3 = h3 && h3 < h2,所以輸出-1。

題目分析:思維題。本題h和w是“等價”的,也就是說一個人的h和w是可以交換的。

解題步驟:在輸入每個人的h和w的時候,如果h < w,交換。用結構體存一個人的h, w,和他是第幾個人,再按w排序。遍歷結構體陣列,判斷當前元素的h是否大於前面最小的h,若是,那麼那個最小的h所對應的人就能成為當前元素的j。若當前元素的h小於前面最小的h,則要更新最小的h的值,但在更新之前要往後遍歷和當前元素w相等的人,最後選擇一個最小的h更新最小的h的值。

方法粗略證明:

設a1 = max(h1, w1), b1 = min(h1, w1), a2 = max(h2, w2), b2 = min(h2, w2)。

若b1 <= b2, 則有b1 <= b2, b1 <= a1, b2 <= a2,若b2 > a1,則有b1 <= a1 < b2 <= a2,也就是b2 > a1時a2也必定大於a1,所以只需要判斷a2是否大於a1, 不需要判斷b2是否大於a1。

AC程式碼:

#include<bits/stdc++.h>

#define ll long long

using namespace std;

const int N = 2e5 + 10;

struct st{

int x, y, z;

bool operator < (const st &X) const{

return y < X.y;

}

}a[N];

int b[N];

void solve(){

int n;

scanf("%d", &n);

for(int i = 1;i <= n;i++){

scanf("%d %d", &a[i].x, &a[i].y);

if(a[i].x < a[i].y) swap(a[i].x, a[i].y);

a[i].z = i;

}

sort(a + 1, a + 1 + n);

int x = a[1].x, y = a[1].y, z = a[1].z;

b[z] = -1;

for(int i = 2;i <= n;i++){

if(a[i].x > x && a[i].y > y) b[a[i].z] = z;

else{

b[a[i].z] = -1;

if(a[i].x < x){

int k = i, j = i + 1;

for(;a[j].y == a[i].y && j <= n;j++){

if(a[j].x > x && a[j].y > y) b[a[j].z] = z;

else{

b[a[j].z] = -1;

if(a[j].x < a[k].x) k = j;

}

}

i = j - 1;

x = a[k].x, y = a[k].y, z = a[k].z;

}

}

}

for(int i = 1;i <= n;i++) printf("%d ", b[i]);

printf("\n");

}

int main(void){

int t;

scanf("%d", &t);

while(t--) solve();

return 0;

}

時間複雜度:O(nlogn),因為用到了排序。

空間複雜度:O(n)。