【PA2013】【BZOJ3839】Działka

来源:互联网 发布:apache安装包下载 编辑:程序博客网 时间:2024/05/01 08:14

Description

平面上有n个不重复的点。每次询问一个边平行坐标轴的矩形内(包含边界)的点组成的凸包的面积。
Input

第一行两个整数k,n(1<=k<=1000000,3<=n<=3000)。
接下来n行,每行两个整数x_i,y_i(0<=x_i,y_i<=k),表示点的坐标。
接下来一行一个整数m(1<=m<=1000000),表示询问数量。
接下来m行,每行四个整数a,b,c,d(0<=a< b<=k,0<=c< d<=k),表示询问的矩形范围为a<=x<=b,c<=y<=d。
Output

对于每个询问输出一行表示面积。保留小数点后一位。
Sample Input

9 7

1 1

1 3

3 3

3 1

6 5

6 6

7 3

3

0 4 0 4

2 7 0 7

3 7 3 6
Sample Output

4.0

10.0

6.0
HINT

Source

150s时限,卡评测好题
考虑把要求的凸包拆分成四部分:左上,左下,右上,右下
分别求每个点对按这四个方向构建凸包的面积(叉积)
对每个询问用线段树+扫描线把叉积累积起来求和然后除以二就是答案
询问限定的那四个范围没法直接处理,所以拆分询问+容斥
这题好厉害…%Claris…

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define MAXN 3010#define GET (ch>='0'&&ch<='9')#define lchild rt<<1,l,mid#define rchild rt<<1|1,mid+1,r#define ln rt<<1#define rn rt<<1|1#define SIZE 1000010#define LL long longusing namespace std;int k,n,m;LL ans;int sta[MAXN],top;inline void in(int &x){    char ch=getchar();x=0;    while (!GET)    ch=getchar();    while (GET) x=x*10+ch-'0',ch=getchar();}LL f[5][MAXN][MAXN];int que[5][SIZE];struct Point{    int x,y,id;    inline friend Point operator -(Point a,Point b) {return (Point){a.x-b.x,a.y-b.y};}    inline friend LL operator *(Point a,Point b)    {return (LL)a.x*b.y-(LL)a.y*b.x;}}s[MAXN];inline LL cross(Point a,Point b,Point c)    {Point A=b-a,B=c-b;return B*A;}inline bool cmp1(Point a,Point b)   {return a.x==b.x?a.y<b.y:a.x<b.x;}inline bool cmp2(Point a,Point b)   {return a.x==b.x?a.y>b.y:a.x<b.x;}inline bool cmp3(Point a,Point b)   {return a.x<b.x;}inline bool cmp4(Point a,Point b)   {return a.y<b.y;}int vis[MAXN],pos;struct seg  {int l,r,x;}tree[SIZE<<2];inline void build(int rt=1,int l=0,int r=k){    tree[rt].x=0;tree[rt].l=l;tree[rt].r=r;int mid=(l+r)>>1;    if (l==r)   return; build(lchild);build(rchild);}inline void modify(int rt,int x,int delta){    int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1; tree[rt].x=delta;    if (L==R)   return;    if (x<=mid) modify(ln,x,delta); else    modify(rn,x,delta);}inline int merge(int x,int y)   {return vis[x]>vis[y]?x:y;}inline int query(int rt,int l,int r){    int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;    if (l<=L&&r>=R) return tree[rt].x;    if (r<=mid) return query(ln,l,r);    if (l>mid)  return query(rn,l,r);    return merge(query(ln,l,mid),query(rn,mid+1,r));}struct Query{    int a,b,c,d;    inline bool operator <(const Query& x)const {return a<x.a;}}q[SIZE],newq[SIZE];int main(){    in(k);in(n);    for (int i=1;i<=n;i++)  in(s[i].x),in(s[i].y),s[i].id=i;    sort(s+1,s+n+1,cmp1);    for (int i=2;i<=n;i++)//A     {        top=0;sta[top]=i;int l=s[sta[top]].id;        for (int j=i-1;j;j--)            if (s[j].y<=s[i].y)            {                while (top&&cross(s[j],s[sta[top]],s[sta[top-1]])<0)    top--;                f[1][l][s[j].id]=f[1][l][s[sta[top]].id]+s[sta[top]]*s[j];sta[++top]=j;            }    }    sort(s+1,s+n+1,cmp2);    for (int i=1;i<n;i++)//B     {        top=0;sta[top]=i;int l=s[sta[top]].id;        for (int j=i+1;j<=n;j++)            if (s[j].y<=s[i].y)            {                while (top&&cross(s[sta[top-1]],s[sta[top]],s[j])<0)    top--;                f[2][l][s[j].id]=f[2][l][s[sta[top]].id]+s[sta[top]]*s[j];sta[++top]=j;            }    }    for (int i=2;i<=n;i++)//C     {        top=0;sta[top]=i;int l=s[sta[top]].id;        for (int j=i-1;j;j--)            if (s[j].y>=s[i].y)            {                while (top&&cross(s[j],s[sta[top]],s[sta[top-1]])>0)    top--;                f[3][l][s[j].id]=f[3][l][s[sta[top]].id]+s[sta[top]]*s[j];sta[++top]=j;            }    }    sort(s+1,s+n+1,cmp1);    for (int i=1;i<n;i++)//D     {        top=0;sta[top]=i;int l=s[sta[top]].id;        for (int j=i+1;j<=n;j++)            if (s[j].y>=s[i].y)            {                while (top&&cross(s[sta[top-1]],s[sta[top]],s[j])>0)    top--;                f[4][l][s[j].id]=f[4][l][s[sta[top]].id]+s[sta[top]]*s[j];sta[++top]=j;            }    }    in(m);    for (int i=1;i<=m;i++)  in(q[i].a),in(q[i].b),in(q[i].c),in(q[i].d);    for (int i=1;i<=m;i++)  newq[i]=(Query){q[i].d,q[i].a,q[i].b,i};//考虑用容斥得到询问答案      sort(s+1,s+n+1,cmp4);sort(newq+1,newq+m+1);int i,j;    for (build(1,0,k),i=j=1;i<=m;i++)    {        while (j<=n&&s[j].y<=newq[i].a) modify(1,s[j].x,s[j].id),vis[s[j++].id]=++pos;        que[1][newq[i].d]=query(1,newq[i].b,newq[i].c);    }    for (int i=1;i<=m;i++)  newq[i]=(Query){q[i].c,q[i].a,q[i].b,i};    sort(s+1,s+n+1,cmp4);sort(newq+1,newq+m+1);    for (build(1,0,k),i=m,j=n;i;i--)    {        while (j&&s[j].y>=newq[i].a)    modify(1,s[j].x,s[j].id),vis[s[j--].id]=++pos;        que[3][newq[i].d]=query(1,newq[i].b,newq[i].c);    }    for (int i=1;i<=m;i++)  newq[i]=(Query){q[i].b,q[i].c,q[i].d,i};    sort(s+1,s+n+1,cmp3);sort(newq+1,newq+m+1);    for (build(1,0,k),i=j=1;i<=m;i++)    {        while (j<=n&&s[j].x<=newq[i].a) modify(1,s[j].y,s[j].id),vis[s[j++].id]=++pos;        que[4][newq[i].d]=query(1,newq[i].b,newq[i].c);    }    for (int i=1;i<=m;i++)  newq[i]=(Query){q[i].a,q[i].c,q[i].d,i};    sort(s+1,s+n+1,cmp3);sort(newq+1,newq+m+1);    for (build(1,0,k),i=m,j=n;i;i--)    {        while (j&&s[j].x>=newq[i].a)    modify(1,s[j].y,s[j].id),vis[s[j--].id]=++pos;        que[2][newq[i].d]=query(1,newq[i].b,newq[i].c);    }    for (int i=1;i<=m;i++)    {        ans=f[1][que[1][i]][que[2][i]]-f[2][que[1][i]][que[4][i]]-f[3][que[3][i]][que[2][i]]+f[4][que[3][i]][que[4][i]];        printf("%lld.%d\n",ans>>1,ans&1ll?5:0);    }}
1 0
原创粉丝点击