[JSOI2018]戰爭(閔可夫斯基和)

懼怕,可憐幾何題
果真不會
題目就是說給你兩個凸包,每次詢問給你一個向量 \(c\) 問你能不能從兩個凸包 \(A\) , \(B\) 裏分別找到一個點 \(a\) , \(b\) 知足 \(a+c=b\)
考慮怎樣的向量能夠知足。
發現只有讓B中的每個點-A中的每個點的集合中的向量能夠知足。由於把上面的式子化一下就是 \(c=b-a\)
凸包B中的點集減去凸包A中的點集。這不是閔可夫斯基和嗎?
因此咱們把兩個凸包的閔可夫斯基和求出,而後每個詢問查看給的向量在不在閔可夫斯基和中便可。
代碼極醜,不過我判向量是否是在凸包裏是把凸包切成上下兩個凸包,而後分類討論求的。node

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long
const int N=501000;
int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return sum*f;
}
int top1,top2,top;
struct node{
    int x,y;
    node (int xx=0,int yy=0){
        x=xx,y=yy;
    }
}stack1[N],stack2[N],a[N],b[N],ans[N],ans1[N];
node operator +(node a,node b){
    return node(a.x+b.x,a.y+b.y);
}
node operator -(node a,node b){
    return node(a.x-b.x,a.y-b.y);
}
bool cmp(node a,node b){
    if(a.x==b.x)return a.y<b.y;
    else return a.x<b.x;
}
int chaji(node a,node b){
    return a.x*b.y-a.y*b.x;
}
bool judge(node a,node b,node c){
    return chaji(b-c,a-b)<=0;
}
int n,m;
void tubao1(){
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++){
        while(top1>1&&judge(a[i],stack1[top1],stack1[top1-1]))top1--;
        stack1[++top1]=a[i];
    }
    int k=top1;
    for(int i=n-1;i>=1;i--){
        while(top1>k&&judge(a[i],stack1[top1],stack1[top1-1]))top1--;
        stack1[++top1]=a[i];
    }
    top1--;
}
void tubao2(){
    sort(b+1,b+1+m,cmp);
    for(int i=1;i<=m;i++){
        while(top2>1&&judge(b[i],stack2[top2],stack2[top2-1]))top2--;
        stack2[++top2]=b[i];
    }
    int k=top2;
    for(int i=m-1;i>=1;i--){
        while(top2>k&&judge(b[i],stack2[top2],stack2[top2-1]))top2--;
        stack2[++top2]=b[i];
    }
    top2--;
}
void sum(){
    for(int i=1;i<=top1;i++)a[i]=stack1[i+1]-stack1[i];
    for(int i=1;i<=top2;i++)b[i]=stack2[i+1]-stack2[i];
    ans[top=1]=stack1[1]+stack2[1];
    int now1=1,now2=1;
    while(now1<=top1&&now2<=top2)top++,ans[top]=ans[top-1]+(chaji(a[now1],b[now2])>=0?a[now1++]:b[now2++]);
    while(now1<=top1)top++,ans[top]=ans[top-1]+a[now1++];
    while(now2<=top2)top++,ans[top]=ans[top-1]+b[now2++];
    top--;
}
bool in(node x){
    if(x.x<ans[1].x||x.x>ans[top1].x)return false;
    if(x.x==ans[1].x){
        if(x.y>=ans[1].y&&x.y<=ans1[1].y)return true;
        else return false;
    }
    if(x.x==ans[top1].x){
        if(x.y>=ans[top1].y&&x.y<=ans1[top2].y)return true;
        else return false;
    }
    int A=lower_bound(ans+1,ans+1+top1,x,cmp)-ans;
    int B=lower_bound(ans1+1,ans1+1+top2,x,cmp)-ans1;
    if(chaji(ans1[B]-x,ans1[B-1]-x)>=0&&chaji(ans[A-1]-x,ans[A]-x)>=0)return true;
    else return false;
}
int q;
signed main(){
    n=read();m=read();q=read();
    for(int i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
    tubao1();
    for(int i=1;i<=m;i++)b[i].x=-read(),b[i].y=-read();
    tubao2();
    sum();
    for(int i=1;i<=top;i++)
        if(ans[i+1].x<ans[i].x){top1=i;break;}
    for(int i=top1;i<=top+1;i++)
        ans1[i-top1+1]=ans[i];
    top2=top+1-top1+1;
    while(ans[top1-1].x==ans[top1].x)top1--;
    while(ans1[top2-1].x==ans1[top2].x)top2--;
    for(int i=1;i<=top2/2ll;i++)swap(ans1[i],ans1[top2-i+1]);
    while(q--){
        int A=read(),B=read();
        node x=node(A,B);
        if(in(x))printf("1\n");
        else printf("0\n");
    }
    return 0;
}
相關文章
相關標籤/搜索