半平面交这个名字好可怕啊……但是其实就是一个单调栈。
我们把所有的一次函数按斜率降序排序,设
i
为当前函数的编号,
如果 calc(i,sk[top])>=calc(sk[top],sk[top−1]) ,即下图的情况:
如果1号点在2号点的右边,显然 sk[top] 这条函数被 sk[top−1] 和 i 这两条函数覆盖,变得不可见,并且对以后的维护也没有了贡献,直接弹出即可。
然后这题就变成了单调栈的水题,直接维护即可。
附上AC代码:
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=5e4+10;
struct note{
int k,b,wz;
bool operator < (const note lyf) const {return k==lyf.k?b>lyf.b:k>lyf.k;}
}a[N];
int n,sk[N],ans[N],top;
inline char nc(void){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &a){
static char c=nc();int f=1;
for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
for (a=0;isdigit(c);a=(a<<3)+(a<<1)+c-'0',c=nc());
return (void)(a*=f);
}
inline double calc(int i,int j) {return (a[i].b-a[j].b)*1.0/(double)(a[j].k-a[i].k);}
int main(void){
freopen("x.txt","r",stdin);
read(n);
for (int i=1; i<=n; ++i) read(a[i].k),read(a[i].b),a[i].wz=i;
sort(a+1,a+1+n);
for (int i=1; i<=n; ++i){
if (a[i].k==a[i-1].k&&i>1) continue;
while (top>1&&calc(sk[top],i)>=calc(sk[top-1],sk[top])) --top;
sk[++top]=i,ans[top]=a[i].wz;
}
sort(ans+1,ans+1+top);
for (int i=1; i<=top; ++i) printf("%d ",ans[i]);
return 0;
}

本文介绍了一种解决半平面交问题的方法——单调栈。通过将所有一次函数按斜率降序排序,利用单调栈来维护函数的可见部分,解决了半平面交的问题。最后给出了AC代码。
590

被折叠的 条评论
为什么被折叠?



