世界
【题目背景】
隔着一面墙,就是两个世界呢……
那无法到达的彼岸,只能去凝望吧……
远方的星辰,又能看到多少呢?
那一个个星星,或许也是一个个世界吧……
【题目描述】
有一个虚无的结界,隔开了两个世界。
人们在结界内游荡,而远方的星辰在结界外。
我们可以把结界看作 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
样例解释
样例解释图如下:
数据范围与提示
测试点编号 | nn | mm | |
---|---|---|---|
1~3 | le 1000≤1000 | le 5≤5 | le 1000≤1000 |
4~6 | le 40000≤40000 | =1=1 | le 40000≤40000 |
7~10 | le 40000≤40000 | le 5≤5 | le 40000≤40000 |
来源
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-ans[i]); return 0; }