题目链接:点击打开链接
题目大意:
在坐标系第一象限有多个矩形,问边长为 t 的左下角坐标(0,0)的正方形覆盖的矩形面积是多少,矩形可能重叠但是无影响。
解题思路:
刚开始完全是蒙蔽的,甚至想到了用扫描线这种东西,后来发现不是矩形面积并。。。就傻了,去大佬博客学习了一发。。。
我是服气的,方法好强。具体做法是线段树中维护三个值 a,b,c。这个值跟面积有关,你可以理解为每个面积都可以表示为 a*t*t+b*t+c;
刚开始可能很懵,其实就是将矩形不断地加入线段树,不断更新维护线段树中a,b,c的值,线段树是以 t 的范围建的。
总体就是分情况讨论,每个矩形对于每个 t 值维护不同的a,b,c的值
(1) t>=max(x2,y2), 对于这些 t 值,他们的 c 直接加上(x2-x1)*(y2-y1);
(2) 如果max(x1,y1)<t<min(x2,y2)(max(x1,y1)<min(x2,y2)的前提下) 就会出现矩形的一部分在正方形中,但是并没有超过矩形上边界和右边界,这时 t 范围内增加的面积就是(t-x1)*(t-y1), 化简之后就是 t*t-(x1+y1)*t+x1*y1,那么 a,b,c分别更新1 -(x1+y1) x1*y1 就好
(3)第三种情况就是 max(min(x2,y2),max(x1,y1))<t<max(x2,y2),这里分 x2>y2 和 y2>x2 两种情况,画到图中分别是正方形超过了矩形上边界但是没有超过右边界,另外一种就是超过了右边界但是没有超过上边界。具体的公式呢可以自己推,画了图以后还是比较容易推的,需要注意的就是 维护的 a,b,c最好用 long long ,别问我咋知道的。。。
细节要注意以下边界,具体看代码吧,
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
#define hash haha
#define double int
using namespace std;
typedef long long ll;
const int N=200000;
int n,m;
ll ans;
struct node
{
int l,r,mid;
ll a,b,c; //long long 型
int lazy;
}t[N<<2];
void build(int l,int r,int rt)
{
int mid=(l+r)>>1;
t[rt].l=l;t[rt].r=r;
t[rt].mid=mid;
t[rt].a=t[rt].b=t[rt].c=0;
t[rt].lazy=0;
if(l==r)
return ;
build(l,mid,lson);
build(mid+1,r,rson);
}
void pushdown(int rt)
{
if(t[rt].lazy) //延迟更新
{
t[lson].a+=t[rt].a;
t[rson].a+=t[rt].a;
t[lson].b+=t[rt].b;
t[rson].b+=t[rt].b;
t[lson].c+=t[rt].c;
t[rson].c+=t[rt].c;
t[rt].lazy=0;
t[lson].lazy=t[rson].lazy=1;
t[rt].a=t[rt].b=t[rt].c=0;
}
}
void update(int l,int r,ll a,ll b,ll c,int rt) //更新a,b,c,的值
{
if(l<=t[rt].l&&t[rt].r<=r)
{
t[rt].lazy=1;
t[rt].a+=a;
t[rt].b+=b;
t[rt].c+=c;
return ;
}
pushdown(rt);
if(l<=t[rt].mid)
update(l,r,a,b,c,lson);
if(r>t[rt].mid)
update(l,r,a,b,c,rson);
}
void query(int k,int rt) //单点查询
{
if(t[rt].l==t[rt].r)
{
ans+=(t[rt].a*k*k+t[rt].b*k+t[rt].c);
return ;
}
pushdown(rt);
if(k<=t[rt].mid)
query(k,lson);
if(k>t[rt].mid)
query(k,rson);
}
int main()
{
int QAQ;
scanf("%d",&QAQ);
while(QAQ--)
{
build(1,200000,1);
scanf("%d",&n);
ll x1,y1,x2,y2;
for(int i=0;i<n;i++)
{
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
update(max(x2,y2),N,0,0,(x2-x1)*(y2-y1),1); //分别对应三种情况 注意边界
if(max(x1,y1)<min(x2,y2))
update(max(x1,y1),min(x2,y2)-1,1,-(x1+y1),x1*y1,1);
int k1=max(min(x2,y2),max(x1,y1)),k2=max(x2,y2);
if(x2>y2)
update(k1,k2-1,0,(y2-y1),-x1*(y2-y1),1);
if(y2>x2)
update(k1,k2-1,0,(x2-x1),-y1*(x2-x1),1);
}
scanf("%d",&m);
int k;
for(int i=0;i<m;i++)
{
ans=0;
scanf("%d",&k); //对于每次查询输出答案
query(k,1);
cout<<ans<<endl;
}
}
}