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)。