先给每个点重新设一个坐标(就是把给定的两个边界强行定成横纵坐标找),这个坐标可以直接通过和两个边界叉积得到。
于是点
i
i
的答案就是其左下方所有点答案的第小值,如果不足
ki
k
i
个点答案就是
i
i
。
于是我们可以考虑整体二分,二分一个时间,把编号
≤Mid
≤
M
i
d
的点强行点亮,看剩下的点中有多少个也能跟着亮。这个二维数点可以横纵坐标分别为一二关键字排序之后,用扫描线+树状数组解决,要注意确定一个点能被点亮之后要立即把这个点加进去扫描。
那么我们就在编号
>Mid
>
M
i
d
的点中确定出哪些点答案
≤Mid
≤
M
i
d
,哪些点
>Mid
>
M
i
d
,我们把后者的
ki
k
i
减去前者带来的贡献,分治下去即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200010
#define ll long long
using namespace std;
int n,w[N],s[N],ans[N];
ll z[N];
int read()
{
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*f;
}
struct pt
{
ll x,y;int id;
void get(int d)
{
x=read();y=read();id=d;
}
ll operator *(pt b)
{
return x*b.y-y*b.x;
}
}L1,L2,a[N],b[N],q[N];
bool cmp(pt a,pt b)
{
if(a.x!=b.x) return a.x<b.x;
return a.y<b.y;
}
struct bit
{
int c[N];
void add(int x,int d)
{
for(;x<=n;x+=(x&-x))
c[x]+=d;
}
int qry(int x)
{
int r=0;
for(;x;x-=(x&-x))
r+=c[x];
return r;
}
}T;
void solve(int L,int R,int l,int r)
{
if(l>r) return ;
if(L==R)
{
for(int i=l;i<=r;i++)
ans[a[i].id]=L;
return ;
}
int Mid=(L+R>>1),mid=l-1,len=r-l+1;
for(int i=r;i>=l;i--)
if(a[i].id<=Mid) {mid=i;break;}
for(int i=l;i<=r;i++)
q[i-l+1].x=a[i].x;
for(int i=l;i<=r;i++)
z[i-l+1]=a[i].y;
sort(z+1,z+len+1);
for(int i=l;i<=r;i++)
q[i-l+1].y=lower_bound(z+1,z+len+1,a[i].y)-z;
for(int i=l;i<=mid;i++)
q[i-l+1].id=0;
for(int i=mid+1;i<=r;i++)
q[i-l+1].id=a[i].id,s[a[i].id]=w[a[i].id];
sort(q+1,q+len+1,cmp);
for(int i=1;i<=len;i++)
if(q[i].id)
{
s[q[i].id]-=T.qry(q[i].y);
if(s[q[i].id]<=0) T.add(q[i].y,1);
}
else T.add(q[i].y,1);
for(int i=1;i<=len;i++)
if((!q[i].id)||s[q[i].id]<=0) T.add(q[i].y,-1);
int tp=mid,ddd;
for(int i=mid+1;i<=r;i++)
if(s[a[i].id]<=0) b[++tp]=a[i];
ddd=tp;
for(int i=mid+1;i<=r;i++)
if(s[a[i].id]>0) w[a[i].id]=s[a[i].id],b[++tp]=a[i];
for(int i=mid+1;i<=r;i++)
a[i]=b[i];
solve(L,Mid,l,ddd);
solve(Mid+1,R,ddd+1,r);
}
int main()
{
n=read();
L1.get(0);L2.get(0);
if(L1*L2==0)
{
ll tmp=0x3f3f3f3f/max(L1.x,L1.y);
L1.x*=tmp;L1.y*=tmp;
L2=L1;L2.x++;
}
if(L1*L2>0) swap(L1,L2);
for(int i=1;i<=n;i++)
a[i].get(i);
for(int i=1;i<=n;i++)
w[i]=read();
for(int i=1;i<=n;i++)
a[i]=(pt){a[i]*L1,L2*a[i],a[i].id};
solve(1,n,1,n);
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}