凸包
Upd10.17
来补坑啦!
总结一下,我做过的凸包题,好像只有两道。
上一道现在还没有A(呜呜
基本的凸包就是一个套路,就是你先化简一个看上去很丑的柿子,然后把它化简成$y=ax+b$的形式
基本上就是有很多个a与b,那么一般就是求所有直线在同一个x条件下的最大值/最小值。
那么就成为了静态凸包的基本问题了:静态维护上凸包/下凸包。
具体的,以下凸包为例。(就做过下凸包,上凸包应该差不多唔
要维护下凸包,实际上就是找在每个x条件下最靠下边的那一条线。
我们把所有的直线按照斜率降序排序,为什么呢
因为我们知道当x趋近正无穷时一定是斜率小的y值小,我们想让这个凸包更加有棱有角
所以要先把一些不够优秀的直线放到凸包里,希冀它能作出一点贡献
那么重点来了,如何维护下凸包?
假如我们现在有一个新加入的直线,我们假设它与栈顶直线的交点横坐标为x1,与栈顶-1直线的交点横坐标为x2.
考虑到加入的直线的斜率一定是单减的,那么画一下图可以发现(其实是我语文不好)当x1
那么此时就可以把栈顶pop掉了,这样一直做,一直到构成下凸包为止。
正确性?画画图显然啊(再次黑框)
例题 [CF535E]Tavas and Pashmaks
设$y_{i}=\frac{S_{1}}{a_{i}}+\frac{S_{2}}{b_{i}}$
那么我们实际上就是要求一对S1,S2使得$y_{i}$最小。
考虑此时有两个未知数,不好搞,总不能搞三维凸包吧。
考虑到S1S2的数据范围是一切实数,那么考虑到将S1S2同时缩小倍数关系选手的y关系不变。
那么就把S2缩成1好咯。
柿子变成了$y_{i}=\frac{A}{a_{i}}+\frac{1}{b_{i}}$
那就好搞咯,静态维护下凸包就好咯。
入门题。(但是我考试时候屁都不会)
代码
1 #include
2 #define lb long double
3 #define N 600005
4 using namespace std;
5 const lb eps=9e-25;
6 inline int read(){
7 register int x=0,f=1;char ch=getchar();
8 while(!isdigit(ch)) f=ch=='-'?-1:1,ch=getchar();
9 while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-48,ch=getchar();
10 return x*f;
11 }
12 struct node{int a,b,id;}q[N],p[N];
13 bool operator < (const node &a,const node &b){return a.a!=b.a?a.ab.b;}
14 int sta[N],top,n;
15 int v[N];
16 map<int,int>M;
17 #define A(x) q[x].a
18 #define B(x) q[x].b
19 #define ID(x) q[x].id
20 long double point(int x,int y){return 1.0L*(B(x)-B(y))*A(x)*A(y)/B(x)/B(y)/(A(y)-A(x));}
21 int main(){
22 // freopen("text.in","r",stdin);
23 n=read();
24 for(int i=1;i<=n;++i) A(i)=read(),B(i)=read(),ID(i)=i;
25
26 sort(q+1,q+n+1);int io=0;
27 for(int i=1;i<=n;++i)
28 if(A(i)==A(i-1)&&B(i)==B(i-1)&&i!=1) M[ID(i)]=M[ID(i-1)];
29 else M[ID(i)]=ID(i),p[++io]=q[i];
30 for(int i=1;i<=io;++i) q[i]=p[i];
31 for(int i=1;i<=io;++i){ED:bool D=0;
32 while(top&&A(sta[top])==A(i)) top--,D=1;
33 while(top>=2&&point(sta[top],i)1],i)) top--,D=1;
34 while(top&&point(sta[top],i)1;
35 if(D) goto ED;
36 sta[++top]=i;
37 }
38 for(int i=1;i<=top;++i) v[M[ID(sta[i])]]=1;
39 for(int i=1;i<=n;++i) if(v[M[i]]) printf("%d ",i);
40 return 0;
41 }
这题卡精