HDU-4533:威威猫系列故事——晒被子(线段树延迟更新+推公式)

本文介绍了一种使用线段树维护三个值a、b、c来解决边长为t的正方形覆盖多个矩形面积的问题。通过不同情况讨论更新a、b、c的值,并提供了详细的解题思路及C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题目链接:点击打开链接


题目大意:

  在坐标系第一象限有多个矩形,问边长为 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;
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值