题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4533
题意:在第一象限中给出若干矩形。现在给出一些询问,每次询问给出一个整数t,问在(0,0)到(t,t)范围的矩形面积和。
思路:参考:http://blog.csdn.net/wh2124335/article/details/8739097。经过计算可以得到,如下算法:
输入询问t
sum=0
遍历所有矩形的四个顶点
如果该顶点在(0,0)-(t,t)的范围内
{
如果当前顶点是它所在矩形的左上角或右下角的点 sum-=[(t,t)和该点形成的矩形的面积]
否则sum+=[(t,t)和该点形成的矩形的面积]
}
返回sum
接下来进行优化:假设当前点坐标是(x,y),那么S=(t-x)*(t-y)。我们可以将其展开:S=t*t-t(x+y)+xy。因此可以将上式分成的三部分分别求和。那么我们可以将所有矩形左下角和右上角的点分到一组a(因为它们和T形成的矩形面积都是做“加”运算),把左上角和右下角的点分到一组b(因为它们和T形成的矩形面积都是做“减”运算)。那么结果可以写成sigma[a中在(t,t)范围内的点和T形成的矩形面积]-sigma[b在(t,t)范围内的点和T形成的矩形面积]。 将a,b中的点分别按max(x,y)排序。对于每次询问t,我们二分找到它在a,b中的位置n,m(即max(x,y)不超过t的最大的下标),答案就是:
Sum(Sa)-Sum(Sb)
=sigma[t*t-t*(x+y)+xy](a中点)-sigma[t*t-t*(x+y)+xy](b中点)
=[sigma(t*t)-sigma(x+y)+sigma(xy)](a中点)-[sigma(t*t)-sigma(x+y)+sigma(xy)](b中点)
然后预处理前i项即可。
struct node
{
int x,y;
node(){}
node(int _x,int _y)
{
x=_x;
y=_y;
}
int get()
{
return max(x,y);
}
};
node a[N],b[N];
i64 s1[N],s2[N],f1[N],f2[N];
int n,m;
int T;
int cmp(node a,node b)
{
return a.get()<b.get();
}
int find(node a[],int t)
{
if(a[1].get()>t) return 0;
if(a[2*n].get()<=t) return 2*n;
int low=1,high=2*n,mid;
while(low<=high)
{
mid=(low+high)>>1;
if(a[mid].get()<=t) low=mid+1;
else high=mid-1;
}
while(high<=2*n&&a[high].get()<=t) high++;
return high-1;
}
void deal()
{
int i,x,y;
i64 ans,p,q,t;
RD(m);
FOR1(i,m)
{
RD(t);
x=find(a,t);
y=find(b,t);
p=x*t*t-s1[x]*t+f1[x];
q=y*t*t-s2[y]*t+f2[y];
ans=p-q;
PR(ans);
}
}
int main()
{
RD(T);
while(T--)
{
RD(n);
int x1,y1,x2,y2,i;
FOR1(i,n)
{
RD(x1,y1,x2,y2);
a[i*2-1]=node(x1,y1);
a[i*2]=node(x2,y2);
b[i*2-1]=node(x1,y2);
b[i*2]=node(x2,y1);
}
sort(a+1,a+2*n+1,cmp);
sort(b+1,b+2*n+1,cmp);
FOR1(i,2*n)
{
s1[i]=s1[i-1]+a[i].x+a[i].y;
s2[i]=s2[i-1]+b[i].x+b[i].y;
f1[i]=f1[i-1]+(i64)a[i].x*a[i].y;
f2[i]=f2[i-1]+(i64)b[i].x*b[i].y;
}
deal();
}
return 0;
}