hdu 4533 威威猫系列故事――晒被子(二重等差数列+差分前缀和)

题意:

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

解析:

真的是细节非常难处理的题目,从有思路到AC,整整敲了一天。
由于矩形之间是相互独立的,而且 ti 又不大,可以把思路转化为每个矩形对时间的贡献是多少。
如果是一个矩形,可以转化成一个正方形,外加一个矩形的情况。
正方形,每增加一秒,其面积对 t 的贡献是一个等差数列的等差数列。
而一个矩形,每增加一秒,其面积对 t 的贡献是一个等差数列。
用差分前缀和,求出到每个时刻,加了多少面积。
注意细节。

my code

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 200005;
int n, m;
ll sum[MAXN], d1[MAXN], d2[MAXN];

void init() {
    memset(sum, 0, sizeof(sum));
    memset(d1, 0, sizeof(d1));
    memset(d2, 0, sizeof(d2));
}

ll cal(ll a1, ll D1, ll D2, ll n) {
    return a1 + n*D1 + n*(n+1)/2 * D2;
}

void add(ll L, ll R, ll a1, ll D1, ll D2) {
    ll len = R - L + 1;
    sum[L] += a1;
    sum[R+1] -= cal(a1, D1, D2, len);

    d1[L] += D1;
    d1[R+1] -= D1 + D2 * len;

    d2[L] += D2;
    d2[R+1] -= D2;
}

void build() {
    for(int i = 1; i < MAXN; i++) {
        d2[i] += d2[i-1];
        d1[i] += d1[i-1] + d2[i];
        sum[i] += sum[i-1] + d1[i];
    }
}

void solve(int x1, int y1, int x2, int y2) {
    if(x1 > y1) {
        swap(x1, y1);
        swap(x2, y2);
    }

    ll a1, D1;
    ll maxLen = max(min(x2, y2) - y1, 0);
    add(y1, y1 + maxLen - 1, 0, y1 - x1 -1, 2);

    if(x2 < y2) {
        a1 = (ll)(x2 - x1) * maxLen;
        D1 = x2 - x1;
        add((ll)y1 + maxLen, y2-1, a1, D1, 0);
    }else {
        a1 = (ll)(y2 - y1) * (y2 - x1);
        D1 = y2 - y1;
        add((ll)y1 + maxLen, x2-1, a1, D1, 0);
    }
    a1 = (ll)(y2 - y1) * (x2 - x1);
    add(max(x2, y2), MAXN, a1, 0, 0);
}

int main() {
    int x1, y1, x2, y2, ti;

    int T;
    scanf("%d", &T);
    while(T--) {
        init();
        scanf("%d", &n);
        for(int i = 0; i < n; i++) {
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            solve(x1, y1, x2, y2);
        }
        build();
        scanf("%d", &m);
        while(m--) {
            scanf("%d", &ti);
            printf("%lld\n", sum[ti-1]);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值