正题
题目链接:http://www.ybtoj.com.cn/contest/119/problem/3
题目大意
给出nnn个点(xi,yi)(x_i,y_i)(xi,yi),mmm次给出(ki,ai)(k_i,a_i)(ki,ai)表示标记所有满足
yj>kixjaiy_j>\frac{k_i}{x_j^{a_i}}yj>xjaiki的未标记点
求每个点的标记时间
1≤n,m≤105,1<ai<101\leq n,m\leq 10^5,1<a_i<101≤n,m≤105,1<ai<10
解题思路
全是乘法所以可以先左右取lnlnln就是
ln(yj)>ln(ki)−ln(xj)×ailn(y_j)>ln(k_i)-ln(x_j)\times a_iln(yj)>ln(ki)−ln(xj)×ai
把x,y,kx,y,kx,y,k取lnlnln然后就是一个顺眼的式子
xj×ai+yi>kix_j\times a_i+y_i>k_ixj×ai+yi>ki
虽然原题说(xi,yi)(x_i,y_i)(xi,yi)是点,但是我们可以换个思路,把(xi,yi)(x_i,y_i)(xi,yi)看成边(f(z)=xiz+yif(z)=x_iz+y_if(z)=xiz+yi),(ai,ki)(a_i,k_i)(ai,ki)看成是点,然后问在每条边下面的编号最小的点是哪个。
这个就很好解决了,考虑整体二分。每次要考虑对于一条边是否有在[L,mid][L,mid][L,mid]编号的点在它下面。可以对于所有的[L,mid][L,mid][L,mid]的点拿出来构成一个下凸壳,然后根据每条边的斜率二分出一个最下面的点,然后只拿这个点判断就好了。
这样就是O(nlog2n)O(n\log^2 n)O(nlog2n)的了,如果肯写归并排序和凸壳用单调队列维护是可以做到O(nlogn)O(n\log n)O(nlogn)的
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+10;
int n,m,f[N],s[N],p[N],p1[N],p2[N],top,pos[N];
double x[N],y[N],k[N],z[N];
double xj(double x1,double y1,double x2,double y2)
{return x1*y2-x2*y1;}
double xl(int a,int b,int c){double y1=k[b]-k[a],x1=z[b]-a[z];double y2=k[c]-k[a],x2=z[c]-z[a];return xj(x1,y1,x2,y2);
}
bool cmp(int x,int y)
{return z[x]<z[y];}
void solve(int Ln,int Rn,int Lm,int Rm){if(Ln>Rn)return;if(Lm==Rm){for(int i=Ln;i<=Rn;i++)f[p[i]]=Lm;return;}int mid=(Lm+Rm)>>1;top=0;sort(pos+Lm,pos+1+mid,cmp);for(int i=Lm;i<=mid;i++){while(top>1&&xl(s[top-1],s[top],pos[i])<=0)top--;s[++top]=pos[i];}sort(pos+Lm,pos+1+mid);int cnt1=0,cnt2=0;for(int i=Ln;i<=Rn;i++){int l=1,r=top-1;while(l<=r){int m=(l+r)>>1;if(xj(z[s[m+1]]-z[s[m]],k[s[m+1]]-k[s[m]],1,x[p[i]])>0)l=m+1;else r=m-1;}if(x[p[i]]*z[s[l]]+y[p[i]]>k[s[l]])p1[++cnt1]=p[i];else p2[++cnt2]=p[i];}for(int i=1;i<=cnt1;i++)p[i+Ln-1]=p1[i];for(int i=1;i<=cnt2;i++)p[Ln+cnt1+i-1]=p2[i];solve(Ln,Ln+cnt1-1,Lm,mid);solve(Ln+cnt1,Rn,mid+1,Rm);return;
}
int main()
{freopen("analysis.in","r",stdin);
// freopen("analysis.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%lf%lf",&x[i],&y[i]);x[i]=log(x[i]);y[i]=log(y[i]);p[i]=i;}for(int i=1;i<=m;i++){scanf("%lf%lf",&k[i],&z[i]);k[i]=log(k[i]);pos[i]=i;}solve(1,n,1,m);for(int i=1;i<=n;i++)if(f[i]==m)puts("-1");else printf("%d\n",f[i]);return 0;
}