ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[ZJOI2019]浙江省选(半平面交)

2019-05-09 10:44:42  阅读:266  来源: 互联网

标签:node int top cross st ZJOI2019 平面 ll 浙江省


一眼看上去就应该能用半平面交去做。

首先考虑怎么求可能得第1名的人:每个人的函数为直线,就是在所有人的半平面交中的上边界者即可获得第一名,这个可以单调队列求解。

再考虑如何求可能得第2名的人:满足2个条件:1、在去掉可能得第1名的人后可以拿第1,这个跳转到上面的过程;2、至多同时被1个能拿第一名的人超越,这个应该在半平面上做一个区间覆盖,可以线段树或者二分求解,我懒得不会写线段树就只写了二分。

第3~m名,可以仿照第2名的过程,做m次半平面交,其实会m=2就是会正解了。

时间复杂度O(nmlogn)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int>pii;
const int N=1e5+7;
struct node{
    ll a,b,c;
    node(){a=b=0,c=1;}
    node(ll x,ll y){if(y<0)x=-x,y=-y;a=x/y;b=x%y;c=y;if(b<0)b+=c,a--;}
    ll ceil(){return a+(b>0);}
    bool operator<(const node&t)const{return a==t.a?b*t.c<t.b*c:a<t.a;}
    bool operator<=(const node&t)const{return a==t.a?b*t.c<=t.b*c:a<t.a;}
}p[N];
int n,m,top,tot,id[N],ans[N],st[N];
ll a[N],b[N];
pii s[N<<1];
bool cmp(int x,int y){return a[x]<a[y]||a[x]==a[y]&&b[x]>b[y];}
node cross(int x,int y){return node(b[y]-b[x],a[x]-a[y]);}
void solve(int k)
{
    top=tot=0;
    p[0]=node(0,1);
    for(int i=1;i<=n;i++)
    if(ans[id[i]]==-1&&a[id[i]]>a[st[top]])
    {
        while(top&&cross(id[i],st[top]).a<p[top].ceil())top--;
        st[++top]=id[i];
        if(top>1)p[top]=cross(st[top-1],id[i]);
    }
    p[top+1]=node(1ll<<60,1);
    for(int i=1;i<=n;i++)
    if(ans[i]>0)
    {
        int l=1,r=top-1,mid,pos=top;
        while(l<=r)
        {
            mid=l+r>>1;
            if(a[st[mid]]>=a[i]||cross(st[mid],i)<=p[mid+1])pos=mid,r=mid-1;
            else l=mid+1;
        }
        s[++tot]=pii(a[st[pos]]>=a[i]?0:cross(st[pos],i).a+1,1);
        l=2,r=top,pos=1;
        while(l<=r)
        {
            mid=l+r>>1;
            if(a[st[mid]]<=a[i]||p[mid]<=cross(st[mid],i))pos=mid,l=mid+1;
            else r=mid-1;
        }
        if(a[st[pos]]>a[i])s[++tot]=pii(cross(st[pos],i).ceil(),-1);
    }
    sort(s+1,s+tot+1);
    for(int i=1,j=1,sum=0;i<=top;i++)
    {
        while(j<=tot&&s[j].first<=p[i].ceil())sum+=s[j++].second;
        if(sum<k)ans[st[i]]=k;
        while(j<=tot&&s[j].first<=p[i+1].a)
        {
            int p=j;
            while(p<=tot&&s[p].first==s[j].first)sum+=s[p++].second;
            if(sum<k)ans[st[i]]=k;
            j=p;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i],&b[i]),id[i]=i,ans[i]=-1;
    sort(id+1,id+n+1,cmp);
    for(int i=1;i<=m;i++)solve(i);
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
}
View Code

 

标签:node,int,top,cross,st,ZJOI2019,平面,ll,浙江省
来源: https://www.cnblogs.com/hfctf0210/p/10837038.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有