原题传送门

看起来挺妙实际很暴力的一题

已知每个选手的分数都是平面上的直线

题目实际就是让我们求每条直线在整点处最大是第几大

我们考虑先对所有的直线进行半平面交(因为\(a_i\)都是正整数,所以比普通的还简单),我们珂以求出哪几个选手最高能拿到rak1

我们再考虑哪几个选手最高珂以拿到rak2

对剩下的人所表示的线段进行半平面交,我们珂以二分查找出之前已经删除的线段每个线段在哪个区间比现在的半平面边界高,打上标记(差分),进行排序,然后扫描线一遍,看到底有哪几个人上面的标记是1的,将这些人的答案标成2

以此类推,我们做m次半平面交,就能求出我们所需答案,时间复杂度\(O(mn\log n)\)

#include <bits/stdc++.h>
#define ll long long
#define N 100005
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll read()
{
register ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct num{
ll a,b,c;
num(){a=b=0,c=1;}
num(register ll x,register ll y)
{
if(y<0)
x=-x,y=-y;
a=x/y;
b=x%y;
c=y;
if(b<0)
b+=c,--a;
}
inline ll floor(){return a;}
inline ll ceil(){return a+(b>0);}
inline bool operator<(const num &x)const{return a==x.a?b*x.c<x.b*c:a<x.a;}
inline bool operator<=(const num &x)const{return a==x.a?b*x.c<=x.b*c:a<x.a;}
}p[N];
int n,m,id[N],s[N],top,tot,ans[N];
ll a[N],b[N];
pair<ll,int> S[N<<1];
inline num cross(register int x,register int y)
{
return num(b[y]-b[x],a[x]-a[y]);
}
inline void work(register int k)
{
p[top=tot=0]=num(0,1);
for(register int i=1;i<=n;++i)
if(ans[id[i]]==-1&&a[id[i]]>a[s[top]])
{
while(top&&cross(id[i],s[top]).floor()<p[top].ceil())
--top;
s[++top]=id[i];
if(top>1)
p[top]=cross(s[top-1],id[i]);
}
p[top+1]=num(1ll<<60,1);
for(register int i=1;i<=n;++i)
if(ans[i]>0)
{
int l=1,r=top-1,res=top;
while(l<=r)
{
int mid=l+r>>1;
if(a[s[mid]]>=a[i]||cross(s[mid],i)<=p[mid+1])
res=mid,r=mid-1;
else
l=mid+1;
}
S[++tot]=make_pair(a[s[res]]>=a[i]?0ll:cross(s[res],i).floor()+1,1);
l=2,r=top,res=1;
while(l<=r)
{
int mid=l+r>>1;
if(a[s[mid]]<=a[i]||p[mid]<=cross(s[mid],i))
res=mid,l=mid+1;
else
r=mid-1;
}
if(a[s[res]]>a[i])
S[++tot]=make_pair(cross(s[res],i).ceil(),-1);
}
sort(S+1,S+1+tot);
for(register int i=1,j=1,x=0;i<=top;++i)
{
while(j<=tot&&S[j].first<=p[i].ceil())
x+=S[j++].second;
if(x<k)
ans[s[i]]=k;
while(j<=tot&&S[j].first<=p[i+1].floor())
{
int l=j;
while(l<=tot&&S[l].first==S[j].first)
x+=S[l++].second;
if(x<k)
ans[s[i]]=k;
j=l;
}
}
}
inline bool cmp(register int x,register int y)
{
return a[x]<a[y]||a[x]==a[y]&&b[x]>b[y];
}
int main()
{
n=read(),m=read();
for(register int i=1;i<=n;++i)
a[i]=read(),b[i]=read(),id[i]=i,ans[i]=-1;
sort(id+1,id+1+n,cmp);
for(register int i=1;i<=m;++i)
work(i);
for(register int i=1;i<=n;++i)
write(ans[i]),putchar(' ');
return 0;
}

【题解】Luogu P5328 [ZJOI2019]浙江省选的更多相关文章

  1. luogu P5328 [ZJOI2019]浙江省选

    传送门 每个人都可以看成一条直线\(y=ax+b\),所以我们要求的是每条线在整点处,上方线的数量的最小值(注意多条直线如果交于同一整点互不影响) 如果\(m=1\),其实只要求出半平面交,然后在半平 ...

  2. 【LuoguP5328】[ZJOI2019]浙江省选

    题目链接 题意 给你一堆斜率和纵截距都为正的直线 ,求对于一个条直线是否存在一个 x 使得在这条直线在 x 处能是前 m 大,输出最高能够达到的排名(排名定义为在 x 处严格大于自己的直线条数+1) ...

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

    一眼看上去就应该能用半平面交去做. 首先考虑怎么求可能得第1名的人:每个人的函数为直线,就是在所有人的半平面交中的上边界者即可获得第一名,这个可以单调队列求解. 再考虑如何求可能得第2名的人:满足2个 ...

  4. Luogu P5296 [北京省选集训2019]生成树计数

    Luogu P5296 [北京省选集训2019]生成树计数 题目链接 题目大意:给定每条边的边权.一颗生成树的权值为边权和的\(k\)次方.求出所有生成树的权值和. 我们列出答案的式子: 设\(E\) ...

  5. [题解] Luogu P5446 [THUPC2018]绿绿和串串

    [题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...

  6. 「ZJOI2019」浙江省选

    在八月来临前补完了zjoi2019 本来是想在八月前做完暑假作业的? 传送门 Description 给\(n\)条斜率为正的直线,询问每条直线是否在某处高度为前\(m\)名,如果是,询问最小排名 S ...

  7. 【题解】Luogu P5327 [ZJOI2019]语言

    原题传送门 看到这种树上统计点对个数的题一般是线段树合并,这题也不出意外 先对这棵树进行树剖,对于每次普及语言,在\(x,y\)两点的线段树上的\(x,y\)两位置打\(+1\)标记,在点\(fa[l ...

  8. 【题解】Luogu P5279 [ZJOI2019]麻将

    原题传送门 希望这题不会让你对麻将的热爱消失殆尽 我们珂以统计每种牌出现的次数,不需要统计是第几张牌 判一副牌能不能和,类似这道题 对于这题: 设\(f[i][j][k][0/1]\)表示前\(i\) ...

  9. Luogu P5279 [ZJOI2019]麻将

    ZJOI2019神题,间接送我退役的神题233 考场上由于T2写挂去写爆搜的时候已经没多少时间了,所以就写挂了233 这里不多废话直接开始讲正解吧,我们把算法分成两部分 1.建一个"胡牌自动 ...

随机推荐

  1. PHP入门之调试

    环境 开发工具VSCode 2019 代码库 自建git 仓库 win7集成环境 PHPStudy2018  具体设置信息:   PHP 5.4.45 ,MySql 5.7 , Apache 2.4 ...

  2. 在Linux下配置git并设置远程仓库

    自己常在云服务器上进行代码的编写,为了更方便的保存工作和管理,便使用了git这个版本管理工具来管理.下面介绍整个服务的配置过程. git的下载安装: 使用以下命令,回车即可,中间过程会有一个按y回车的 ...

  3. 【Python笔记】1、格式化输出(%用法和format用法)

    转自:https://www.cnblogs.com/fat39/p/7159881.html 一.格式化输出1.整数的输出%o —— oct 八进制%d —— dec 十进制%x —— hex 十六 ...

  4. R 指定安装镜像的方法

    方法一 options(repos=structure(c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))) install ...

  5. 初始化错误——从一个简单的算例看UDF各个宏的调用顺序

    感谢西安交通大学en_phert的问题和尝试 Fluent版本:Fluent 19.0 Visual Studio版本:Visual Studio 2013 在UDF的宏的调用中大家常看见下图: 这个 ...

  6. Vs2017添加.NET Standard项目出现黄色未引用的SDK

    项目打开文件夹位置,按住shift键,执行dotnet restore命令

  7. unicode欺骗—— hctf - admin

    查看源代码,发现<!-- you are not admin --> 提示要以管理员身份登陆 尝试注册管理员账号,提示The username has been registered 于是 ...

  8. Gamma阶段第四次scrum meeting

    每日任务内容 队员 昨日完成任务 明日要完成的任务 张圆宁 #91 用户体验与优化https://github.com/rRetr0Git/rateMyCourse/issues/91(持续完成) # ...

  9. 从技术角度看Pacs厂商

    天健PACS较早从事影像医院处理系统,为国外系统或设备以OEM方式提供软件模块.天健的PACS里面三维重建.容积重建.血管分析.虚拟腔镜.头部灌注等部分是用西安盈谷科技的,手术麻醉和重症监护系统是奥迪 ...

  10. SpringBoot激活profiles

    多环境是最常见的配置隔离方式之一,可以根据不同的运行环境提供不同的配置信息来应对不同的业务场景,在SpringBoot内支持了多种配置隔离的方式,可以激活单个或者多个配置文件. 激活Profiles的 ...