原题传送门

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

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

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

我们考虑先对所有的直线进行半平面交(因为\(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. Linux 和 windows下查看运行命令的位置

    经常遇到要查看某个命令的运行文件在哪儿! 比如说vue cli,经常使用vue命令创建项目,如果你对nodejs的全局包安装目录了解可能一下就找到了, 蛋疼的是不一定每个命令都是nodejs下的,有可 ...

  2. Comet OJ - Contest #15 题解

    传送门 \(A\) 咕咕 const int N=1005; int a[N],n,T; int main(){ for(scanf("%d",&T);T;--T){ sc ...

  3. pwd函数实现

    /* * 文件名:mypwd.c * 描述: 实现简单的pwd命令 */ #include<stdio.h> #include<stdlib.h> #include<di ...

  4. centos8.0安装docker

    背景简介: 前两天红帽正式发布了RHEL8,网上同时也有了CentOS8,一直在接触容器方面,为了尝鲜,下载了CentOS8,并尝试安装docker,不料竟然还报了个错(缺少依赖),故及时记录一下,方 ...

  5. HTTPS加密协议过程

    1.客户端发起https请求 指用户在浏览器中输入一个https网址,然后链接到server的443端口 2.服务端的配置 在服务端向CA机构申请SSL数字证书.SSL证书就是一对公钥和私钥.公钥相当 ...

  6. 【BigData】Java基础_数组

    什么是数组?数据是可以装一组数据的变量 1.定义数组 float[] arr1 = new float[10]; // 可以装10个float数据 int[] arr2 = new int[10]; ...

  7. FZU Monthly-201906 tutorial

    FZU Monthly-201906 tutorial 题目(难度递增) easy easy-medium medium medium-hard hard 思维难度 AE B DG CF H A. X ...

  8. 【转】Android 破解视频App去除广告功能详解及解决办法总结

    Android 破解视频App去除广告功能 作为一个屌丝程序猿也有追剧的时候,但是当打开视频app的时候,那些超长的广告已经让我这个屌丝无法忍受了,作为一个程序猿看视频还要出现广告那就是打我脸,但是我 ...

  9. CMU Advanced DB System - MVCC

    https://zhuanlan.zhihu.com/p/40208895 Mysql的MVCC实现 https://severalnines.com/database-blog/comparing- ...

  10. LocalDateTime

    @Component public class DateUtil { public final static String EMPTY_SRING = ""; public fin ...