【题解】Luogu P5328 [ZJOI2019]浙江省选
原题传送门
看起来挺妙实际很暴力的一题
已知每个选手的分数都是平面上的直线
题目实际就是让我们求每条直线在整点处最大是第几大
我们考虑先对所有的直线进行半平面交(因为\(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]浙江省选的更多相关文章
- luogu P5328 [ZJOI2019]浙江省选
传送门 每个人都可以看成一条直线\(y=ax+b\),所以我们要求的是每条线在整点处,上方线的数量的最小值(注意多条直线如果交于同一整点互不影响) 如果\(m=1\),其实只要求出半平面交,然后在半平 ...
- 【LuoguP5328】[ZJOI2019]浙江省选
题目链接 题意 给你一堆斜率和纵截距都为正的直线 ,求对于一个条直线是否存在一个 x 使得在这条直线在 x 处能是前 m 大,输出最高能够达到的排名(排名定义为在 x 处严格大于自己的直线条数+1) ...
- [ZJOI2019]浙江省选(半平面交)
一眼看上去就应该能用半平面交去做. 首先考虑怎么求可能得第1名的人:每个人的函数为直线,就是在所有人的半平面交中的上边界者即可获得第一名,这个可以单调队列求解. 再考虑如何求可能得第2名的人:满足2个 ...
- Luogu P5296 [北京省选集训2019]生成树计数
Luogu P5296 [北京省选集训2019]生成树计数 题目链接 题目大意:给定每条边的边权.一颗生成树的权值为边权和的\(k\)次方.求出所有生成树的权值和. 我们列出答案的式子: 设\(E\) ...
- [题解] Luogu P5446 [THUPC2018]绿绿和串串
[题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...
- 「ZJOI2019」浙江省选
在八月来临前补完了zjoi2019 本来是想在八月前做完暑假作业的? 传送门 Description 给\(n\)条斜率为正的直线,询问每条直线是否在某处高度为前\(m\)名,如果是,询问最小排名 S ...
- 【题解】Luogu P5327 [ZJOI2019]语言
原题传送门 看到这种树上统计点对个数的题一般是线段树合并,这题也不出意外 先对这棵树进行树剖,对于每次普及语言,在\(x,y\)两点的线段树上的\(x,y\)两位置打\(+1\)标记,在点\(fa[l ...
- 【题解】Luogu P5279 [ZJOI2019]麻将
原题传送门 希望这题不会让你对麻将的热爱消失殆尽 我们珂以统计每种牌出现的次数,不需要统计是第几张牌 判一副牌能不能和,类似这道题 对于这题: 设\(f[i][j][k][0/1]\)表示前\(i\) ...
- Luogu P5279 [ZJOI2019]麻将
ZJOI2019神题,间接送我退役的神题233 考场上由于T2写挂去写爆搜的时候已经没多少时间了,所以就写挂了233 这里不多废话直接开始讲正解吧,我们把算法分成两部分 1.建一个"胡牌自动 ...
随机推荐
- 洛谷2051 [AHOI2009]中国象棋
题目链接 题意概述:n行m列棋盘放若干个棋子每行每列最多两个求方案总数,答案对9999973取模. 可以比较容易看出这是个dp,设f[i][j][k]表示前i行j列放1个棋子k列放2个棋子的方案总数. ...
- linux安装yasm报错
进入yasm-1.2.0, 输入指令 ./configure //编译yasm make && make install //安装yasm,安装完成即可. 报错信息 make[2]: ...
- nginx 日志打印响应时间 request_time 和 upstream_response_time
设置log_format,添加request_time,$upstream_response_time,位置随意 og_format main '"$request_time" ...
- ECharts饼图自定义
[本文出自天外归云的博客园] 实现: 1.饼块可点击(点击饼块跳转到百度) 2.饼块自定义标签显示(显示个数.占比) 3.自定义标签连接线样式(虚线) 前端php代码如下: <!DOCTYPE ...
- revit 碰撞检测相关
Revit二次开发:由房间获取房间的墙 之前用的方法是由房间边界构成的Solid,计算与该Solid相交的Element,然后判断是否为墙.相对来说这个方法比较通用,可以检索出房间的楼板.窗户 ...
- Egret HTML5游戏开发指南
Egret HTML5游戏开发指南 下载地址:https://pan.baidu.com/s/1fuxllvmRhWXoWDwH4gxN9g 关注微信公众号获取提取码: 输入:egrt 获取提取码
- hackbar简单安装使用教程
安装hackbar: 在火狐的附加组件中搜索“hackbar”,将它添加到火狐浏览器中, 重启后Firefox后安装完成,按F9键打开我们就会看到在地址栏下面会出现一个大框框就是hackbar了 框框 ...
- python对不同类型文件(doc,txt,pdf)的字符查找
python对不同类型文件的字符查找 TXT文件: def txt_handler(self, f_name, find_str): """ 处理txt文件 :param ...
- java js ur特殊格式处理 json 特殊格式处理
url特殊格式处理: js中使用 encodeURIComponent() 编码对应的value $.ajax({ type: "post", url: "/tb_are ...
- php对数组遍历的两种方式示例
在对 php 数组遍历时,一般经常使用 foreach 来遍历,很少用 while 来遍历,在下面的代码中作一个对比. <?php $content = ["ID" => ...