FJ省队集训DAY2 T2
思路:我们可以考虑三角剖分,这样问题就变成考虑三角形的选取概率和三角形内有多少个点了。
先用树状数组预处理出三角剖分的三角形中有多少个点,然后用线段树维护,先用原点极角排序,然后枚举i,再以i极角排序,此时线段树的作用就来了,每次到一个询问的教室点,我们就在线段树里面查找之前的概率,统计贡献即可。
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #define MAXN 2005 struct Point{ double x,y; double p,ang; int id; }p[MAXN],Cur[MAXN]; double P[MAXN],T[MAXN * 4]; int n,m,rk[MAXN],s[MAXN],f[MAXN][MAXN]; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } bool cmp(Point p1,Point p2){ return p1.ang<p2.ang; } void build (int k,int l,int r){ if (l==r) {T[k]=1-P[Cur[l].id];return;} int mid=(l+r)>>1; build(k*2,l,mid); build(k*2+1,mid+1,r); T[k]=T[k*2]*T[k*2+1]; } double query(int k,int l,int r,int x,int y){ if (y<l||x>r) return 1.0; if (x<=l&&r<=y) return T[k]; int mid=(l+r)>>1; return query(k*2,l,mid,x,y)*query(k*2+1,mid+1,r,x,y); } void init(){ n=read();m=read(); for (int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); for (int i=n+1;i<=n+m;i++) scanf("%lf%lf%lf",&p[i].x,&p[i].y,&P[i]); for (int i=1;i<=n+m;i++) p[i].ang=atan2(p[i].y,p[i].x); } void add(int pos){ for (;pos<=n+m;pos+=(pos)&(-pos)) s[pos]++; } int sum(int pos){ int res=0; for (;pos;pos-=(pos)&(-pos)) res+=s[pos]; return res; } void Sort(int mid){ int tot=0; for (int i=0;i<=n+m;i++) if (i!=mid) Cur[++tot]=p[i],Cur[tot].ang=atan2(Cur[tot].y-p[mid].y,Cur[tot].x-p[mid].x); std::sort(Cur+1,Cur+1+tot,cmp); for (int i=1;i<=tot;i++) rk[Cur[i].id]=i; } int range(int l,int r){ if (l<=r) return sum(r)-sum(l-1); return sum(n+m)-sum(l-1)+sum(r); } void solve(){ for (int i=1;i<=n+m;i++) p[i].ang=atan2(p[i].y,p[i].x),p[i].id=i; std::sort(p+1,p+1+n+m,cmp); for (int i=1;i<=n+m+1;i++) if (p[i].id>n){ Sort(i); for (int j=0;j<=n+m;j++) s[j]=0; for (int j=i+1;j<=n+m+1;j++){ if (p[j].id<=n&&p[j].id) add(rk[p[j].id]); f[p[i].id][p[j].id]=std::max(0,range(rk[p[j].id],rk[0])); } for (int j=0;j<=n+m;j++) s[j]=0; for (int j=i-1;j;j--){ if (p[j].id<=n&&p[j].id) add(rk[p[j].id]); f[p[i].id][p[j].id]=std::max(0,range(rk[0],rk[p[j].id])); } } } double ask(int l,int r){ if (l>r) return query(1,1,n+m-1,l,n+m-1)*query(1,1,n+m-1,1,r-1); else return query(1,1,n+m-1,l,r-1); } void linear(){ double ans=0.0; int tot=0; for (int i=1;i<=n+m;i++) if (p[i].id>n){ tot=0; for (int j=1;j<=n+m;j++) if (i!=j) Cur[++tot]=p[j],Cur[tot].ang=atan2(p[j].y-p[i].y,p[j].x-p[i].x); std::sort(Cur+1,Cur+1+tot,cmp); build(1,1,tot); for (int j=1,Pp=2;j<=tot;j++){ for(;(Cur[j].x - p[i].x) * (Cur[Pp].y - p[i].y) - (Cur[j].y - p[i].y) * (Cur[Pp].x - p[i].x) > 0;) Pp=Pp%tot+1; if (Cur[j].id>n){ double pr=ask(Pp,j)*P[p[i].id]*P[Cur[j].id]; if (p[i].x * Cur[j].y - p[i].y * Cur[j].x < 0) ans -= pr * f[p[i].id][Cur[j].id]; else ans += pr * f[p[i].id][Cur[j].id]; } } } printf("%.9lf\n",ans); } int main(){ init(); solve(); linear(); }