UOJ #495. 晒被子
【题目描述】:
在平面直角坐标系上晒了许多块被子,被子呈矩形,边均与x或y轴平行,在(0,0)处有一个水源,水不断从(0,0)处溢出,在第t秒形成了一个以(0,0)(0,t)(t,0)(t,t)为顶点的正方形水域,在其中的被子都会被弄湿,询问某些时刻被弄湿的被子的总面积(同一格子的不同被子算多次)。
【输入描述】:
第一行2个整数n、q,表示被子总数和询问次数。
接下来n行每行4个整数x1、y1、x2、y2,表示一条被子的位置是以(x1,y1)(x2,y2)为左下角和右上角顶点的矩形。
接下来q行每行1个整数t,表示询问第t秒被子弄湿的总面积。
【输出描述】:
共q行表示每次询问的答案。
【样例输入】:
3 3
0 0 3 3
1 0 3 2
0 1 2 3
1
2
3
【样例输出】:
1
8
17
【样例说明】:
样例输入说明,下载图片
【时间限制、数据范围及描述】:
时间:1s 空间:256M
30%的数据0<=t,x1,y1,x2,y2<=1000。
50%的数据n<=1000,q<=1000。
另有20%的数据q=1。
100%的数据n<=50000,q<=100000,0<=t,x1,y1,x2,y2<=5×10^6,x1<x2,y1<y2。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=500010; bool p[N]; int a[N],b[N],c[N],d[N]; int n,m,t,l,x,x1,x2,y1,y2; long long t1,t2,tot,s,ss,s2,ans[N]; void add(int x,int y,int z) { if(x>y) swap(x,y); s+=z; l++; a[l]=x; b[l]=(l+1)/2; c[l]=z; l++; a[l]=y; b[l]=l/2; c[l]=z; } void kp(int l,int r) { int i=l,j=r,m=a[(i+j)/2]; while(i<=j) { while(a[i]<m) i++; while(a[j]>m) j--; if(i<=j) { swap(a[i],a[j]); swap(b[i],b[j]); swap(c[i],c[j]); i++; j--; } } if(i<r) kp(i,r); if(l<j) kp(l,j); } int main () { //freopen("sbz.in","r",stdin); //freopen("sbz.out","w",stdout); scanf("%d%d",&n,&m); s=0; for(int i=1; i<=n; i++) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); if(x2>0&&y2>0) add(x2,y2,1); if(x1>0&&y2>0) add(x1,y2,-1); if(x2>0&&y1>0) add(x2,y1,-1); if(x1>0&&y1>0) add(x1,y1,1); } for(int i=1; i<=m; i++) { scanf("%d",&x); l++; a[l]=x; b[l]=i; c[l]=0; } kp(1,l); tot=0; s2=0; a[0]=0; for(int i=1; i<=l; i++) { t1=a[i-1]; t2=a[i]; ss=t2*t2-t1*t1; tot+=ss*s; ss=(t2-t1)*s2; tot+=ss; if(c[i]==0) ans[b[i]]=tot; else if(!p[b[i]]) { s2+=a[i]*c[i]; s-=c[i]; p[b[i]]=true; d[b[i]]=a[i]; } else s2-=d[b[i]]*c[i]; } for(int i=1; i<=m; i++) printf("%lld\n",ans[i]); return 0; }