Codeforces Round #693E / Problem 1472E
1.原题链接:
https://codeforces.com/problemset/problem/1472/E
2.题意:
多组输入。
对于每组数据,输入一个n,表示有n个方块,接下来n行输入方块的长和宽。
对于每个方块,询问是否存在某个方块的长和宽都小于该方块,注意,方块可以旋转,使长宽互换,存在则输出任意一块的id ,不存在则输出-1
3.解题思路:
小技巧,为了解决长宽互换的问题,我们在输入时,使更小的值为长,更大的值为宽,反之亦可解题。
首先对所有方块按照一边排序(无论长或宽都行),然后开一个前缀数组pre ,维护另一边数据截至目前的最小值和最小值方块的id。
以按照长排序,维护宽的前缀数组,为例:
对于某一方块,首先对它的长进行二分查找,找到值小于该方块长 的最大下标。然后查询该下标维护的最小宽是否小于该方块的宽。如果小于,则该方块的答案就是所维护最小宽记录的id。
因为我们首先二分查找保证了,该下标位置和之前所有的长都小于该方块的长,然后,我们再查询截至目前下标维护的最小的宽,就能保证能找出同时符合长和宽都小于该方块的解。如不能找出,则无解。
4.AC代码
#include <iostream>
#include <algorithm>
using namespace std;
const int Maxn=2e5+7;
int t;
int n;
struct box
{
int id;
int x;
int y;
};
bool cmp(box a,box b)
{
if(a.x==b.x)
return a.y<b.y;
else
return a.x<b.x;
}
box arr[Maxn];
int ans[Maxn]; //用于记录答案的数组
int pre[Maxn][2]; //pre[i][0] 表示截至目前最小的值 pre[i][1]表示该值的id
//二分,输入一个num 找到值x小于num的最大下标
int fun(int num)
{
//不存在比num小的值,因此不存在下标
if(arr[1].x>=num)
return -1;
int l=1;
int r=n;
int mid;
while(l<=r)
{
mid=(l+r)/2;
if(arr[mid].x>=num)
r=mid-1;
else if(arr[mid+1].x<num)
l=mid+1;
else
return mid;
}
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
int x,y;
for(int i=1;i<=n;i++)
{
cin>>x>>y; //长和宽中使得更小的为长,更大的为宽
arr[i].x=min(x,y);
arr[i].y=max(x,y);
arr[i].id=i;
}
sort(arr+1,arr+1+n,cmp);
pre[1][0]=arr[1].y;
pre[1][1]=arr[1].id;
for(int i=2;i<=n;i++)
{
//如果当前的宽小于之前维护的宽,则当前的宽为截止目前最小的宽,并更新id
if(arr[i].y<pre[i-1][0])
{
pre[i][0]=arr[i].y;
pre[i][1]=arr[i].id;
}
else //否则当前的值 等于截止到上一个方块的值
{
pre[i][0]=pre[i-1][0];
pre[i][1]=pre[i-1][1];
}
}
ans[arr[1].id]=-1;
for(int i=2;i<=n;i++)
{
int index = fun(arr[i].x);
if(index!=-1&&pre[index][0]<arr[i].y)
ans[arr[i].id]=pre[index][1];
else
ans[arr[i].id]=-1;
}
for(int i=1;i<n;i++)
cout<<ans[i]<<" ";
cout<<ans[n]<<endl;
}
return 0;
}