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();
}

 

posted @ 2016-07-04 21:57  GFY  阅读(250)  评论(0编辑  收藏  举报