列表

详情


NC14823. 寄蒜几盒

描述

在二维平面上有n条直线,这些直线会将平面划分成若干个区域。给定m个点,求每个点所在的区域的面积。
聪明的读者会发现有些点所在的区域面积是无穷大的。R姓出题人早就想到了这一点,所以他给出了一个实数L,由额外的四条直线x=L,x=-L,y=L,y=-L 框定了一个有限的平面区域,并且所有的询问点都在这个框定的平面区域内部。
聪明绝顶的读者会发现如果询问点恰好落在某条直线上或者离某条直线的距离非常近,那么精度误差会严重影响答案。R姓出题人早就想到了这一点,所以在他造的数据中,任意一个询问点距离任意一条直线的距离大于10-7

输入描述

第一行两个正整数n,m和一个正实数L。
接下来n行每行三个实数A,B,C,表示这条直线的方程为Ax+By+C=0
接下来m行,第i行两个实数xi,yi,表示第i个点的坐标。

输出描述

输出m行,每行一个实数,第i行输出的实数表示第i个点所在的区域的面积。保留两位小数。

示例1

输入:

2 4 3
1 1 -1
-1 1 -1
0 2
-2 1
2 1
0 0

输出:

4.00
8.50
8.50
15.00

说明:

对于100%的数据,n<=500,m<=100000
对于100%的数据,输入数据的绝对值<=107,且输入数据最多保留两位小数。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 897ms, 内存消耗: 97348K, 提交时间: 2019-08-07 16:18:03

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stdio.h>
#include <vector>
#include <map>
#include <set>
using namespace std;
const int mod = 1e5 + 9;
const double eps = 1e-9, pi = acos(-1.);
struct point {
    double x, y;
    bool operator<(const point &temp) const {
        if (fabs(x - temp.x) < eps)
            return y < temp.y - eps;
        return x < temp.x;
    }
};
struct line {
    int id;
    point l, r;
    bool operator<(const line &temp) const {
        double lx, rx, mx, y1, y2;
        lx = max(l.x, temp.l.x);
        rx = min(r.x, temp.r.x);
        mx = 0.5 * (lx + rx);
        if (fabs(r.x - l.x) < eps)
            y1 = 0.5 * (l.y + r.y);
        else
            y1 = l.y + (mx - l.x) / (r.x - l.x) * (r.y - l.y);
        if (fabs(temp.r.x - temp.l.x) < eps)
            y2 = 0.5 * (temp.l.y + temp.r.y);
        else
            y2 = temp.l.y + (mx - temp.l.x) / (temp.r.x - temp.l.x) * (temp.r.y - temp.l.y);
        return y1 < y2 - eps;
    }
};
int belong[255555][2], cnt_be[255555];
double a[255555], b[255555], c[255555];
struct an {
    int l, r;
    bool operator<(const an &temp) const {
        if (l == temp.l)
            return r < temp.r;
        return l < temp.l;
        //    if(l<temp.l)
        //    return true;
        // if(temp.l<l)
        // return false;
        // return r<temp.r;
    }
};
long long fe[mod][33];
int num[mod];
int vl[mod][33];
line lines[550], ls[500000];
set<line> ha;
set<line>::iterator it, ht;
int cnt_ls;
map<point, int> hs;
point pt[110000], list[300000], now;
int n, m, cnt_list, fir;
int dx[] = { -1, 1, 0, 0 };
int dy[] = { 0, 0, -1, 1 };
int vec[555][555], num_vec[555];
double ans[110000];
struct pp {
    int id;
    double x, y;
    bool vis;
    bool operator<(const pp &temp) const {
        int f1, f2;
        if (y > eps || (fabs(y) < eps && x < 0))
            f1 = 1;
        else if (y < -eps)
            f1 = -1;
        else
            f1 = 0;
        if (temp.y > eps || (fabs(temp.y) < eps && temp.x < 0))
            f2 = 1;
        else if (temp.y < -eps)
            f2 = -1;
        else
            f2 = 0;
        if (f1 != f2)
            return f1 < f2;
        return y * temp.x < x * temp.y - eps;
    }
};
vector<pp> adj[255000];
pp awp;
bool cmp1(int id1, int id2) { return list[id1] < list[id2]; }
double l;
struct quyu {
    vector<int> vp;
    double area;
};
quyu qr[255555];
struct xxx {
    int id, flag;
    double x;
    bool operator<(const xxx &temp) const {
        if (fabs(x - temp.x) < eps)
            return flag < temp.flag;
        return x < temp.x;
    }
};
xxx x[1000000];
int num_area, cnt_x;
void norm(double &theta) {
    while (theta > pi - eps) theta -= 2 * pi;
    while (theta < -pi + eps) theta += 2 * pi;
}
int binary(int left, int right, vector<pp> &adj, pp rf) {
    int mid;
    while (left <= right) {
        mid = (left + right) >> 1;
        if (adj[mid] < rf)
            left = mid + 1;
        else if (rf < adj[mid])
            right = mid - 1;
        else
            return mid;
    }
    return -1;
}
void go(int uu, int vv) {
    int i, j, s, p, q, id, ie;
    double theta;
    if (adj[uu][vv].vis)
        return;
    adj[uu][vv].vis = true;
    qr[num_area].vp.push_back(uu);
    id = adj[uu][vv].id;
    pp rf;
    rf.x = -adj[uu][vv].x;
    rf.y = -adj[uu][vv].y;
    ie = binary(0, adj[id].size() - 1, adj[id], rf);
    go(id, (ie - 1 + adj[id].size()) % adj[id].size());
}
int main() {
    scanf("%d%d%lf", &n, &m, &l);
    int i, j, s, p, q, u, v;
    for (i = 0; i < n; i++) scanf("%lf%lf%lf", &a[i], &b[i], &c[i]);
    for (i = n; i < n + 4; i++) {
        a[i] = dx[i - n];
        b[i] = dy[i - n];
        c[i] = l;
    }
    n += 4;
    cnt_list = 0;
    hs.clear();
    for (i = 0; i < n; i++) {
        num_vec[i] = 0;
        for (j = 0; j < n; j++) {
            if (i == j)
                continue;
            double aa, bb;
            aa = (a[i] * b[j] - b[i] * a[j]);
            bb = (-c[i] * b[j] + b[i] * c[j]);
            if (fabs(aa) < eps)
                continue;
            now.x = bb / aa;
            bb = (-c[j] * a[i] + a[j] * c[i]);
            now.y = bb / aa;
            if (now.x > l + eps || now.x < -l - eps || now.y > l + eps || now.y < -l - eps)
                continue;
            if (!hs.count(now)) {
                list[cnt_list++] = now;
                hs[now] = cnt_list - 1;
            }
            vec[i][num_vec[i]++] = hs[now];
        }
        sort(vec[i], vec[i] + num_vec[i], cmp1);
        int nn = 0;
        for (j = 0; j < num_vec[i]; j++) {
            if (nn == 0 || vec[i][nn - 1] != vec[i][j])
                vec[i][nn++] = vec[i][j];
        }
        num_vec[i] = nn;
        for (j = 0; j < num_vec[i] - 1; j++) {
            u = vec[i][j];
            v = vec[i][j + 1];
            awp.id = v;
            awp.x = list[vec[i][j + 1]].x - list[vec[i][j]].x;
            awp.y = list[vec[i][j + 1]].y - list[vec[i][j]].y;
            adj[u].push_back(awp);
            awp.id = u;
            awp.x = list[vec[i][j]].x - list[vec[i][j + 1]].x;
            awp.y = list[vec[i][j]].y - list[vec[i][j + 1]].y;
            adj[v].push_back(awp);
        }
    }
    for (i = 0; i < cnt_list; i++) sort(adj[i].begin(), adj[i].end());
    num_area = 0;
    for (i = 0; i < cnt_list; i++) {
        for (j = 0; j < adj[i].size(); j++) adj[i][j].vis = false;
    }
    for (i = 0; i < cnt_list; i++) {
        for (j = 0; j < adj[i].size(); j++) {
            if (fabs(list[i].x - l) < eps || fabs(list[i].x + l) < eps || fabs(list[i].y - l) < eps ||
                fabs(list[i].y + l) < eps)
                continue;
            if (!adj[i][j].vis) {
                qr[num_area].vp.clear();
                fir = i;
                go(i, j);
                num_area++;
            }
        }
    }
    cnt_ls = 0;
    cnt_x = 0;
    memset(num, 0, sizeof(num));
    for (i = 0; i < num_area; i++) {
        qr[i].area = 0;
        if (qr[i].vp.size() >= 3) {
            for (j = 1; j < qr[i].vp.size() - 1; j++) {
                double x1, y1, x2, y2;
                x1 = list[qr[i].vp[j]].x - list[qr[i].vp[0]].x;
                y1 = list[qr[i].vp[j]].y - list[qr[i].vp[0]].y;
                x2 = list[qr[i].vp[j + 1]].x - list[qr[i].vp[0]].x;
                y2 = list[qr[i].vp[j + 1]].y - list[qr[i].vp[0]].y;
                qr[i].area += 0.5 * (x1 * y2 - x2 * y1);
            }
            for (j = 0; j < qr[i].vp.size(); j++) {
                an awp;
                now.x = list[qr[i].vp[j]].x;
                now.y = list[qr[i].vp[j]].y;
                awp.l = qr[i].vp[j];
                ls[cnt_ls].l = now;
                now.x = list[qr[i].vp[(j + 1) % qr[i].vp.size()]].x;
                now.y = list[qr[i].vp[(j + 1) % qr[i].vp.size()]].y;
                ls[cnt_ls].r = now;
                awp.r = qr[i].vp[(j + 1) % qr[i].vp.size()];
                if (fabs(ls[cnt_ls].l.x - ls[cnt_ls].r.x) < eps)
                    continue;
                if (ls[cnt_ls].r < ls[cnt_ls].l) {
                    swap(ls[cnt_ls].l, ls[cnt_ls].r);
                    swap(awp.l, awp.r);
                }
                int id;
                long long state = 1LL * awp.l * cnt_list + awp.r;
                int la = state % mod;
                for (s = 0; s < num[la]; s++) {
                    if (fe[la][s] == state)
                        break;
                }
                if (s >= num[la])  // if(!fe.count(awp))
                {
                    fe[la][num[la]] = state;
                    vl[la][num[la]++] = cnt_ls;
                    // fe[awp]=cnt_ls;
                    ls[cnt_ls].id = cnt_ls;
                    cnt_be[cnt_ls] = 0;
                    belong[cnt_ls][cnt_be[cnt_ls]++] = i;
                    cnt_ls++;
                    id = cnt_ls - 1;
                } else {
                    id = vl[la][s];
                    // id=fe[awp];
                    belong[id][cnt_be[id]++] = i;
                }
                x[cnt_x].flag = 0;
                x[cnt_x].x = ls[id].l.x;
                x[cnt_x++].id = id;
                x[cnt_x].flag = -1;
                x[cnt_x].x = ls[id].r.x;
                x[cnt_x++].id = id;
            }
        }
    }
    for (i = 0; i < m; i++) {
        scanf("%lf%lf", &pt[i].x, &pt[i].y);
        x[cnt_x].flag = 1;
        x[cnt_x].id = i;
        x[cnt_x++].x = pt[i].x;
    }
    sort(x, x + cnt_x);
    ha.clear();
    int nm = 0;
    for (i = 0; i < cnt_x && nm < m; i++) {
        if (x[i].flag == 0)
            ha.insert(ls[x[i].id]);
        else if (x[i].flag < 0)
            ha.erase(ls[x[i].id]);
        else {
            nm++;
            line bwp;
            bwp.l = bwp.r = pt[x[i].id];
            it = ha.lower_bound(bwp);
            int bs[2], as[2], cnt_bs = cnt_be[it->id], cnt_as = 0;
            for (j = 0; j < cnt_bs; j++) bs[j] = belong[it->id][j];
            it--;
            cnt_as = cnt_be[it->id];
            for (j = 0; j < cnt_as; j++) as[j] = belong[it->id][j];
            int ch = -1;
            for (j = 0; j < cnt_bs; j++) {
                for (s = 0; s < cnt_as; s++) {
                    if (bs[j] == as[s])
                        ch = as[s];
                }
            }
            ans[x[i].id] = qr[ch].area;
        }
    }
    for (i = 0; i < m; i++) printf("%.2f\n", ans[i]);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 240ms, 内存消耗: 7644K, 提交时间: 2019-01-07 17:59:44

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1e-7

bool same(double a,double b)
{
 return (a-b>-eps && a-b<eps);
}

int n,m,t;
double x,y,z;
double L;
double ans[100010];

struct point{double x,y;};

struct et{point s;int id;} q[100010];

struct line
{
 double A,B,C,k;
 void create(double a,double b,double c)
 {
  A=a,B=b,C=c;
  if (same(b,0)) k=1e50;else k=-a/b;
 }
} l[510];

struct it{int l1,l2;point c;} c[260000];



bool operator <(line a,line b)//按照斜率对直线进行排序
{
 if (same(a.k,b.k)) 
 {
  if (!same(a.B,0)) return a.C/a.B<b.C/b.B;
  return a.C/a.A>b.C/b.A;
 }
 return a.k<b.k;
}

bool operator <(point a,point b)//按照x坐标对点进行排序
{
 if (same(a.x,b.x)) return a.y<b.y;
 return a.x<b.x;
}

bool operator <(et a,et b)
{
 return a.s<b.s;
}

bool operator <(it a,it b)//对直线的交点进行排序
{
 if (same(a.c.x,b.c.x) && same(a.c.y,b.c.y))
 {
  if (a.l1==b.l1) return a.l2<b.l2;
  return a.l1<b.l1;
 }
 return a.c<b.c;
}

point cp(line a,line b)//求两条直线的交点
{
 point ret;
 ret.y=(b.C*a.A-a.C*b.A)/(a.B*b.A-a.A*b.B);
 if (!same(a.A,0)) ret.x=-(ret.y*a.B+a.C)/a.A;
 else ret.x=-(ret.y*b.B+b.C)/b.A;
 return ret;
}

double cross(point a,point b)//计算叉积
{
 return a.x*b.y-a.y*b.x;
}

double count(line a,point p)
{
 return a.A*p.x+a.B*p.y+a.C;
}

void init()
{
 l[n].create(-1,0,L);
 l[n+1].create(-1,0,-L);
 l[n+2].create(0,1,-L);
 l[n+3].create(0,1,L);
 n+=4;
 sort(l,l+n);
 t=0;
 
 //计算直线的交点
 for (int i=0;i<n;i++)
  for (int j=i+1;j<n;j++)
  if (!same(l[i].k,l[j].k))
  {
   c[t].l1=i,c[t].l2=j,c[t].c=cp(l[i],l[j]);
   t++;
  }
 
 sort(q,q+m);
 sort(c,c+t);
 
}

int xl[510],fd[510];
double s[510];
vector<int> que[510];
point last[510];

int bs(point p)//二分点的位置
{
 int L=0,R=n,mid;
 while (L<R)
 {
  mid=(L+R)/2;
  if (count(l[xl[mid]],p)>0) R=mid;else L=mid+1;
 }
 return L;
}

void updata(int x)//x区域的面积计算完毕
{
 for (int i=0;i<que[x].size();i++) ans[que[x][i]]=s[x];
 s[x]=0;
 que[x].clear();
}

void solve()
{
 int j=0;
 for (int i=0;i<n;i++) xl[i]=i,fd[i]=i;
 for (int i=0;i<t;i++)
 {
  if (i==51)
  {
   j++;
   j--;
  }
  
  while (q[j].s<c[i].c && j<m)
  {
   int x=bs(q[j].s);//二分确定点在第x个区域
   que[x].push_back(q[j].id);//将第j个点加入第x区域的队列等待计算
   j++;
  }
  
  int a=fd[c[i].l1],b=fd[c[i].l2];
  double xa=cross(c[i].c,last[a]),xb=cross(last[b],c[i].c);
  
  if (a+1!=b) printf("wa on %d\n",i);
  
  s[b]-=xa+xb;
  updata(b);
  
  s[a]+=xa;
  s[b+1]+=xb;
 
  last[a]=last[b]=c[i].c;
  
  swap(xl[a],xl[b]);
  fd[xl[a]]=a;
  fd[xl[b]]=b; 
 }
}

int main()
{
 scanf("%d%d%lf",&n,&m,&L);
 for (int i=0;i<n;i++) 
 {
  scanf("%lf%lf%lf",&x,&y,&z);
  if (same(y,0))
  {
   if (x>0) x=-x,z=-z;
  }
  else if (y<0) x=-x,y=-y,z=-z;
  l[i].create(x,y,z);
 }
 for (int i=0;i<m;i++) scanf("%lf%lf",&q[i].s.x,&q[i].s.y);
 for (int i=0;i<m;i++) q[i].id=i;
 
 init();
 solve();
 for (int i=0;i<m;i++) printf("%.2lf\n",ans[i]/(-2));
 return 0;
}

上一题