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 long
using 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);
}
}