世界

世界

【题目背景】

隔着一面墙,就是两个世界呢……

那无法到达的彼岸,只能去凝望吧……

远方的星辰,又能看到多少呢?

那一个个星星,或许也是一个个世界吧……

【题目描述】

有一个虚无的结界,隔开了两个世界。

人们在结界内游荡,而远方的星辰在结界外。

我们可以把结界看作 xx 轴,那么人们都在 xx 轴下方,而星星都在 xx 轴上方。

人们本应该能看到所有的星星,但是结界外( xx 轴上方)出现了几座墙,挡住了人们的视线。墙是平行于 xx 轴的。

现在想问,每个人分别能看到多少星星。

输入格式

第一行三个数,n,m,qn,m,q,表示星星的数量,墙数,人数。

下面 nn 行,每行两个整数 x,yx,y,表示星星的坐标,其中 y>0y>0

下面 mm 行,每行三个整数 x_1,x_2,yx1,x2,y,表示两端的 xx 坐标和 yy 坐标。其中 y>0,x_1<x_2y>0,x1<x2

下面 qq 行,每行两个整数 x,yx,y,表示人的坐标,其中 y<0y<0 。

坐标的绝对值不超过 10^6106 。

数据保证星星和墙不重叠。

输出格式

qq 行,第 ii 行一个数表示第 ii 个人能看到的星星数量。

样例

样例输入1

6 2 3
0 2
0 15
5 7
15 15
35 12
45 10
5 20 5
25 40 10
0 -5
5 -10
20 -15

样例输出1

4
3
2

样例解释

样例解释图如下:

数据范围与提示

测试点编号nnmmqq
1~3 \le 10001000 \le 55 \le 10001000
4~6 \le 4000040000 =1=1 \le 4000040000
7~10 \le 4000040000 \le 55 \le 4000040000

来源

CSP-S 2019模拟 淮阴

 


Solution

 

有一个很妙的转化:
连接一块板的两端和人,所得的线交x轴与l,r
连接一块板的两端和星星,所得的线交x轴与L,R
那么人看不到星星当且仅当L<=l<r<=R
m=1时就是类似二位偏序的统计了。
m>1时可以2^5枚举板,考虑板的交集容斥即可。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 40005
#define inf 1e16
#define db double
using namespace std;
int n,m,q,fl[6],tot,sb,sc,ans[maxn],Max,tr[maxn*4];
db p[maxn*4];
struct node{
    int id;db x,y;
    int l,r;
}a[6][2],s[maxn],t[maxn],b[maxn],c[maxn];
int read(){
    char ch;int v=0,f=1;
    while(!isdigit(ch=getchar())&&ch!='-');
    if(ch=='-')f=-1;else v=v+ch-48;
    while(isdigit(ch=getchar()))v=(v<<1)+(v<<3)+ch-48;
    return v*f;
}
db cr(node A,node B){
    if(A.x==B.x)return A.x;
    db k=(A.y-B.y)/(A.x-B.x);
    db tmp=-A.y/k+A.x;return tmp;
}
int find(db x){
    int l=1,r=tot;
    while(l<r){
        int mid=l+r+1>>1;
        if(p[mid]<=x)l=mid;
        else r=mid-1;
    }
    return l;
}
void init(){
    sb=sc=0;tot=0;
    for(int i=1;i<=n;i++){
        db L=-inf,R=inf;
        for(int j=1;j<=m;j++){
            if(!fl[j])continue;
            L=max(L,cr(a[j][0],s[i]));R=min(R,cr(a[j][1],s[i]));
            
        }
        if(L<=R){
            node x;x.x=L,x.y=R;
            b[++sb]=x,p[++tot]=L,p[++tot]=R;
        }
    }
    for(int i=1;i<=q;i++){
        db L=-inf,R=inf;
        for(int j=1;j<=m;j++){
            if(!fl[j])continue;
            L=max(L,cr(a[j][0],t[i]));R=min(R,cr(a[j][1],t[i]));
        }
        if(L<=R){
            node x;x.id=t[i].id;x.x=L,x.y=R;
            c[++sc]=x,p[++tot]=L,p[++tot]=R;
        }
    }
    if(!sb||!sc)return;
    sort(p+1,p+tot+1);tot=unique(p+1,p+tot+1)-p-1;
    Max=0;
    for(int i=1;i<=sb;i++){
//        b[i].l=lower_bound(p+1,p+tot+1,b[i].x)-p;
//        b[i].r=lower_bound(p+1,p+tot+1,b[i].y)-p;
        b[i].l=find(b[i].x);b[i].r=find(b[i].y);
        Max=max(Max,b[i].r);
    }
    for(int i=1;i<=sc;i++){
//        c[i].l=lower_bound(p+1,p+tot+1,c[i].x)-p;
//        c[i].r=lower_bound(p+1,p+tot+1,c[i].y)-p;
        c[i].l=find(c[i].x),c[i].r=find(c[i].y);
        Max=max(Max,c[i].r);
    }
}
bool cmp(node A,node B){return A.l<B.l;}
void add(int i,int v){for(;i<=Max;i+=i&-i)tr[i]+=v;}
int ask(int i){int sum=0;for(;i;i-=i&-i)sum+=tr[i];return sum;}
void clac(int op){
    init();if(!sb||!sc)return;
    sort(b+1,b+sb+1,cmp);
    sort(c+1,c+sc+1,cmp);
    for(int i=1;i<=Max;i++)tr[i]=0;
    int j=1;
    for(int i=1;i<=sc;i++){
        while(j<=sb&&b[j].l<=c[i].l)add(b[j].r,1),j++;
        int tmp=ask(Max)-ask(c[i].r-1);
        if(op)ans[c[i].id]+=tmp;
        else ans[c[i].id]-=tmp;
    }
}
int main(){
    n=read();m=read();q=read();
    for(int i=1;i<=n;i++)s[i].x=read(),s[i].y=read();
    for(int i=1;i<=m;i++)a[i][0].x=read(),a[i][1].x=read(),a[i][0].y=a[i][1].y=read();
    for(int i=1;i<=q;i++)t[i].x=read(),t[i].y=read(),t[i].id=i;
    for(int S=1;S<(1<<m);S++){
        int co=0;
        for(int i=0;i<m;i++)if(S&(1<<i))fl[i+1]=1,co++;
        clac(co&1);
        for(int i=1;i<=m;i++)fl[i]=0; 
    }
    for(int i=1;i<=q;i++)printf("%d\n",n-ans[i]);
    return 0;
}

 

 
 
 
posted @ 2019-11-13 07:33  liankewei123456  阅读(206)  评论(0编辑  收藏  举报