#4629. 世界
题目描述
> 隔着一面墙,就是两个世界呢……
> 那无法到达的彼岸,只能去凝望吧……
> 远方的星辰,又能看到多少呢?
> 那一个个星星,或许也是一个个世界吧……
有一个虚无的结界,隔开了两个世界。
人们在结界内游荡,而远方的星辰在结界外。
我们可以把结界看作 $x$ 轴,那么人们都在 $x$ 轴下方,而星星都在 $x$ 轴上方。
人们本应该能看到所有的星星,但是结界外( $x$ 轴上方)出现了几座墙,挡住了人们的视线。墙是平行于 $x$ 轴的。
现在想问,每个人分别能看到多少星星。
数据范围
$n\le 40000$,$m\le 5$,$q\le 40000$,坐标的绝对值不超过 $10^6$。
题解
考虑只有一堵墙的话,可以把星星和人分别对墙的两个端点做延长线到x轴上,那人看不到星星应当是星星的区间包含人的区间。于是就是个二位偏序。
考虑多堵墙,容斥即可。具体的就是星星和人对状态为 $1$ 的墙的区间取个交集,那如果人不能通过这些墙的任意一个看到星星的条件也是星星的区间包含人的区间。
代码
#include <bits/stdc++.h> #define db long double #define _(d) while(d(isdigit(c=getchar()))) using namespace std; int D(){ char c;int x,f=0;_(!)f|=(c==45);x=c^48;_()x=(x<<3)+(x<<1)+(c^48);return f?-x:x; } const int N=8e4+5; int n,m,q,t,f[N],a[N],G,h[35]; db g[N]; struct O{ int x,y,z; }sr[N],wl[7],pr[N]; struct P{ db l,r;int x; }p[N]; inline db L(O u,O v){ return ((db)u.x*v.z-(db)v.x*u.y)/((db)v.z-u.y); } inline db R(O u,O v){ return ((db)u.x*v.z-(db)v.y*u.y)/((db)v.z-u.y); } bool cmp(P A,P B){ return A.l==B.l?A.x<B.x:A.l<B.l; } inline void upd(int x){ for (;x;x-=x&-x) a[x]++; } inline int qry(int x){ int v=0; for (;x<=G;x+=x&-x) v+=a[x]; return v; } inline void work(int s){ t=0; for (int i=1;i<=n;i++){ db l=-2e18,r=2e18; for (int j=1;j<=m;j++) if (s&(1<<(j-1))){ if (sr[i].y<=wl[j].z){ r=l-1;break; } db x=L(sr[i],wl[j]),y=R(sr[i],wl[j]); l=max(x,l);r=min(r,y); } if (l<=r) p[++t]=(P){l,r,0},g[t]=r; } for (int i=1;i<=q;i++){ db l=-2e18,r=2e18; for (int j=1;j<=m;j++) if (s&(1<<(j-1))){ db x=L(pr[i],wl[j]),y=R(pr[i],wl[j]); l=max(x,l);r=min(r,y); } if (l<=r) p[++t]=(P){l,r,i},g[t]=r; } sort(p+1,p+t+1,cmp); sort(g+1,g+t+1);G=unique(g+1,g+t+1)-g-1; for (int r,i=1;i<=t;i++){ r=lower_bound(g+1,g+G+1,p[i].r)-g; if (p[i].x) f[p[i].x]+=h[s]*qry(r); else upd(r); } for (int i=1;i<=G;i++) a[i]=0; } void W(int x){ if (x<10) putchar(x^48); else W(x/10),putchar((x%10)^48); } int main(){ n=D(),m=D(),q=D();h[0]=-1; for (int i=1;i<=n;i++) sr[i].x=D(),sr[i].y=D(); for (int i=1;i<=m;i++) wl[i].x=D(),wl[i].y=D(),wl[i].z=D(); for (int i=1;i<=q;i++) pr[i].x=D(),pr[i].y=D(); for (int i=1;i<(1<<m);i++) h[i]=-h[i-(i&-i)]; for (int i=(1<<m)-1;i;i--) work(i); for (int i=1;i<=q;i++) W(n-f[i]),putchar('\n'); return 0; }