【2020NIO.AC省选模拟#10】C. 寄蒜几盒

题目链接

原题解:

可以发现,假设我们把凸多边形看做障碍,一个点没有被染色当且仅当在它的位置上能看到凸多边形任意两条相对的边中的一条(也就是能看到至少$dfrac{n}{2}$条边)。

对于每个询问点,我们只需要从某个点出发二分出能看到或不能看到的边的区间,就能知道它有没有被染色。

(可以使用__int128)

补充:

虽然有直线划分,但本题并不是用半平面交做。

代码(100分):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define IL inline
#define RG register
using namespace std;
typedef long long LL;
typedef __int128 Int;
#define RI RG int
#define RC RG char
const int N=1e5;

    int L,R,i,l,m,n,o,q,r,s,t;
    LL a[N],b[N],x,y;

IL bool cmp(RI u,RI v){
    return (Int)0<=(Int)(a[u]-x)*(b[v]-y)
                  -(Int)(a[v]-x)*(b[u]-y);
}

IL bool solve(){
    scanf("%lld%lld",&x,&y);
    x^=(LL)t*s*s*s;
    y^=(LL)t*s*s*s;
    o=cmp(n>>1,(n>>1)+1);
    if(o==cmp(n,1))
        return o;
        
    for(l=1,r=n>>1;l<r;){
        m=l+r>>1;
        cmp(m,m+1)^o?l=m+1:r=m;
        
    }
    for(L=l,l=n>>1,r=n-1;l<r;){
        m=l+r+2>>1;
        cmp(m,m+1)^o?r=m-1:l=m;
        
    }
    
    R=l;
    if(o)
        return (n>>1)<R-L+1;
    else 
        return R-L+1<(n>>1);
    
}

int main(){
    scanf("%d%d",&t,&n);
    for(RI i=1;i<=n;i++)
        scanf("%lld%lld",&a[i],&b[i]);
    scanf("%d",&q);
    for(RI i=1;i<=q;i++){
        s+=o=solve();
        puts(o?"DA":"NE");
        
    }
    
    return 0;
    
}
View Code
原文地址:https://www.cnblogs.com/Hansue/p/13089656.html