1 2 1 1 3 3 2 2 4 4 5 1 2 3 4 5
0 1 5 8 8
解题思路:
如上:
当矩形在对角线的某一侧时,是最简单的。假设是对角线下方。。只要让result[x1] ----- result[x2+1] 之间的值加上y2 - y1 就行了
实现是这样的“ 让matrix[x1+1] = y2 - y1; matrix[x2+1] = y1 - y2; (加一是因为面积在当前点才开始生效)
(for i = x1 ---> x2) gg += matrix[i]; result[i] = result[i-1]+ gg;
明显在i== x1+1 的时候 gg = y2 - y1 ,以后再x1 到 x2 之间的result都会加 y2 - y2 在x2 + 1处加上 y1 - y 2 ,gg == 0了
当是正方形的时候,假设只有一个正方形,在x1 处 vx = 1;以后每个在 x1 到x2之间的result += 1(vx)
当是明显正方形每扩大一个就要增加两个单位面积 于是 设 fx += vx 这样以后每步都可以把两边多出的面积加起来了。
让result += fx * 2 + fv 但是当正方形消失了怎么办呢? 那么再建立一个数组 flag[] 在正方形消失的位置修改fv ,这个位置fv = fv - 正方形当前的高度,
那么之后这个正方形就不影响了 因为 fx,vx == 0了
假设是其他情况发生,那么他们都可以被分解成上面说的矩形和正方形, 于是算法得出了。
复杂度是 200000的 ,优化的效果不明显 就假设是o(N)的吧
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
__int64 matrix[200009];//记录普通矩形影响
__int64 result[200009];//结果
__int64 flag [200009];//消除已经消失的正方形影响
__int64 square[200009];//记录正方形开始点
int query[20009];//查询
void haha(int low, int high)//处理正方形情况
{
if(low >= high) return ;
square[low+1] += 1;
square[high+1] -= 1;
flag[high+1] -= (high - low);
}
void make(int low,int high, int width)//处理普通矩形
{
if(width <= 0) return;
matrix[low+1] += width;
matrix[high+1] -= width;
}
int main()
{
int t;
scanf("%d",&t);
__int64 gg = 0;
__int64 fx = 0;
__int64 vx = 0;
int x1,x2,y1,y2, N;
__int64 lager;
while(t--)
{
memset(matrix, 0, sizeof(matrix));
memset(flag, 0, sizeof(flag));
memset(square, 0, sizeof(square));
scanf("%d",&N);
int maxM = 0;
lager = 0;
for(int i = 0;i < N; i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
maxM = max(maxM,x2);//用于优化的,其实可以不用
maxM = max(maxM,y2);
if(x1 > y1)//右下角
{
make(x1,x2,min(x1,y2)-y1);
}
if(x2 > y2)//右上角
{
make(y2,x2,y2-max(x1,y1));
}
if(y1 > x1)//左下角
{
make(y1,y2,min(x2,y1)-x1);
}
if(x2 < y2)//左上角
{
make(x2,y2,x2-max(x1,y1));
}
haha(max(x1,y1),min(x2,y2));//正方形
}
int q ,maxn1 = 0;
scanf("%d",&q);
int f = 0;
for(int i = 0;i < q; i++)
{
scanf("%d",&query[i]);
maxn1 = max(maxn1,query[i]);//用于优化的,
}
for(int i = 0;i < maxn1+10 ;i++)//枚举每个时间t下被影响的面积
{
if(maxM + 3 < i) break;
gg += matrix[i];
vx += square[i];
fx += flag[i];
result[i] = result[i-1]+ gg + vx + fx*2;
lager = max(lager,result[i]);
fx += vx;
}
for(int i = 0;i < q; i++)
{
if(query[i] > maxM + 3) printf("%I64d\n",lager);
else printf("%I64d\n",result[query[i]]);
}
}
return 0;
}