zoukankan      html  css  js  c++  java
  • 【YbtOJ#853】平面标记

    题目

    题目链接:https://www.ybtoj.com.cn/contest/119/problem/3

    (n,mleq 10^5;0<x,yleq 1000;0<k<10^6;0<a<10)

    思路

    (x'_i=frac{1}{x_i}),那么也就是标记 (y_i>kcdot x_i^a)
    看到指数不难想到取对数,这样就转化为了 (ln(y_i)>ln(k)+aln(x))
    也就是给你若干条直线,问你每一个点最早在哪一条直线的上方。
    考虑整体二分,假设当前直线区间为 ([l,r]),点的区间为 ([ql,qr]),取 (mid=frac{l+r}{2}),那么只需要知道 ([ql,qr]) 的点是否在 ([l,mid]) 所构成的上凸壳内。如果是,说明 ([l,mid]) 中所有的直线都高于这个点,往右扔,否则往左扔。
    然后考场上脑抽发现 (ln) 最多是 (7) 然后保留 (6) 位小数写李超树被卡到 (90) 分,考后无论怎么调精度最高 (95)
    其实只需要单调栈维护一下上凸壳就可以了,然后指针扫一下可以做到 (O(nlog n))
    强制在线的话就线段树上维护凸壳在线二分。复杂度 (O(nlog ^2n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=100010;
    const double eps=1e-8;
    int n,m,top,st[N],ans[N];
    
    struct node
    {
    	double x,y;
    	int id;
    }a[N],b[N],sav[N];
    
    bool cmp1(node x,node y)
    {
    	return (fabs(x.x-y.x)<eps)?(x.y<y.y):(x.x>y.x);
    }
    
    bool cmp2(node x,node y)
    {
    	return x.x<y.x;
    }
    
    double get(int i,int j)
    {
    	if (fabs(b[j].x-b[i].x)<eps) return 1e14;
    	return (b[i].y-b[j].y)/(b[j].x-b[i].x);
    }
    
    void solve(int l,int r,int ql,int qr)
    {
    	if (l==r)
    	{
    		for (int i=ql;i<=qr;i++)
    			if (a[i].y>a[i].x*b[l].x+b[l].y)
    				ans[a[i].id]=l;
    		return;
    	}
    	int mid=(l+r)>>1,pl=l-1,pr=r+1;
    	for (int i=l;i<=r;i++)
    		if (b[i].id<=mid) sav[++pl]=b[i];
    			else sav[--pr]=b[i];
    	for (int i=l;i<=pl;i++) b[i]=sav[i];
    	for (int i=pr;i<=r;i++) b[i]=sav[r-i+pr];
    	pl=ql-1; pr=qr+1; top=0;
    	for (int i=l;i<=mid;i++)
    	{
    		while (top>1 && get(i,st[top-1])>=get(i,st[top])) top--;
    		st[++top]=i;
    	}
    	for (int i=ql,j=1;i<=qr;i++)
    	{
    		while (j<top && get(st[j],st[j+1])<a[i].x) j++;
    		if (a[i].y>a[i].x*b[st[j]].x+b[st[j]].y) sav[++pl]=a[i];
    			else sav[--pr]=a[i];
    	}
    	for (int i=ql;i<=pl;i++) a[i]=sav[i];
    	for (int i=pr;i<=qr;i++) a[i]=sav[qr-i+pr];
    	solve(l,mid,ql,pl); solve(mid+1,r,pr,qr);
    }
    
    int main()
    {
    	freopen("analysis.in","r",stdin);
    	freopen("analysis.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%lf%lf",&a[i].x,&a[i].y);
    		a[i].x=log(1.0/a[i].x); a[i].y=log(a[i].y);
    		a[i].id=i;
    	}
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%lf%lf",&b[i].y,&b[i].x);
    		b[i].y=log(b[i].y); b[i].id=i;
    	}
    	memset(ans,-1,sizeof(ans));
    	sort(b+1,b+1+m,cmp1);
    	sort(a+1,a+1+n,cmp2); 
    	solve(1,m,1,n);
    	for (int i=1;i<=n;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    USART串口通信实验
    EXTI 外部中断
    NVIC中断优先级管理
    实验1 跑马灯实验
    redis集群部署---一台主机
    zookeeper服务启动报错---Error contacting service. It is probably not running.
    shell脚本学习笔记
    最短路径算法——Floyd算法
    一篇文章学懂Shell脚本(摘抄)
    VIM空格和TAB转换
  • 原文地址:https://www.cnblogs.com/stoorz/p/14421574.html
Copyright © 2011-2022 走看看