hdu4533

题意:

给你N个矩形,每个矩形给出左下角坐标,右上角坐标,有M个询问,每个询问给出一个时间t,问(0,0),(t,t)的范围内矩形的面积和(重叠的也算)。

分析:

首先我们观察到求的是(0,0),(t,t)的范围内矩形的面积和(重叠的也算)。
①这是一个正方形,那么我们可以尝试将其转换成一个线段。
(因为n≤20000)
②注意“重叠的面积”。
于是我们分成三个阶段。

这里写图片描述
在这个阶段,计算面积的公式为(tx1)(ty1),因式分解之后,得到三个系数的值。这种情况是max(x1,y1)<min(x2,y2),所以更新的区间是[max(x1,y1),min(x2,y2)]

这里写图片描述
在这个阶段,计算的公式为(tx1)(ty1)(tx1)(ty2),同样因式分解之后,得到三个系统的值。这种情况更新的区间要小心,应该是[max(x1,y2)+1,x2]。另外一种矩阵情况也是一样的,不再赘述。

这里写图片描述
最后,面积就应为(x2x1)(y2y1)。更新的范围就是max(x2,y2)+1

然后就可以用线段树高兴地维护ax2+bx+c的值了

代码:

#include<cstdio>
#include<cstring>

using namespace std;
const long long N=2000100;
long long n,m,x1,y1,x2,y2,t;
struct tree{long long l,r,a,b,c;}g[4*N];

long long max(long long x,long long y){return x>y?x:y;}
long long min(long long x,long long y){return x<y?x:y;}
void build(long long rt,long long l,long long r)
{
    g[rt].a=g[rt].b=g[rt].c=0;
    g[rt].l=l;g[rt].r=r;
    if (l==r) return;
    long long mid=(l+r)/2;
    build(2*rt,l,mid);
    build(2*rt+1,mid+1,r);
}

void pushdown(long long rt)
{
    g[2*rt].a+=g[rt].a;
    g[2*rt].b+=g[rt].b;
    g[2*rt].c+=g[rt].c;
    g[2*rt+1].a+=g[rt].a;
    g[2*rt+1].b+=g[rt].b;
    g[2*rt+1].c+=g[rt].c;
    g[rt].a=g[rt].b=g[rt].c=0;
}

long long query(long long rt,long long k)
{
    long long l=g[rt].l,r=g[rt].r;
    if (l==r) return k*k*g[rt].a+k*g[rt].b+g[rt].c;
    long long mid=(l+r)/2;
    pushdown(rt);
    if (k<=mid) 
        return query(2*rt,k); else
        return query(2*rt+1,k);
}

void update(long long rt,long long ll,long long rr,long long a,long long b,long long c)
{
    long long l=g[rt].l,r=g[rt].r;
    if (ll<=l && r<=rr)
    {
        g[rt].a+=a;
        g[rt].b+=b;
        g[rt].c+=c;
        return;
    }
    long long mid=(l+r)/2;
    if (ll<=mid) update(2*rt,ll,rr,a,b,c);
    if (rr> mid) update(2*rt+1,ll,rr,a,b,c);
}

int main()
{
    long long T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        build(1,1,200000);
        for (long long i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            update(1,max(x2,y2)+1,200000,0,0,(x2-x1)*(y2-y1));
            if (x2<y2)
                update(1,max(x2,y1)+1,y2,0,x2-x1,y1*(x1-x2)); else
                update(1,max(x1,y2)+1,x2,0,y2-y1,x1*(y1-y2));
            if (max(x1,y1)<min(x2,y2))
                update(1,max(x1,y1),min(x2,y2),1,-(x1+y1),x1*y1);
        }
        scanf("%d",&m);
        for (long long i=1;i<=m;i++)
        {
            scanf("%I64d",&t);
            printf("%I64d\n",query(1,t));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值