矩形面积交 [区间树状数组, 扫描线]

矩 形 面 积 交 矩形面积交



正 解 部 分 \color{red}{正解部分}

每个矩形提出其 左边右边 , 每条边都使用三元组 ( l , r , f l a g , t y p e ) (l, r, flag, type) (l,r,flag,type)表示, 放置对应的 x x x 坐标上,

使用一条 扫描线 从左向右扫, 如下图计算 橙色询问矩形 的答案,

计算相交面积 s 2 s_2 s2 时, 考虑使用 y y y 总相交面积 s 3 s_3 s3 减去 y y y 相交 x x x 不相交面积 s 1 s_1 s1 .

s 3 s_3 s3 可以在 询问矩形 右边 通过查询 [ l , r ] [l, r] [l,r] 的面积和得到 .



使用前面 黄色虚线面积 减去 绿色面积 得到 s 1 s_1 s1 .

区间树状数组 :

  • 区间查询: [ 1 , r ] [1, r] [1,r], r e s = ∑ i = 1 r ∑ j = 1 i d [ j ] = ∑ i = 1 r ( r − i + 1 ) × d [ i ] = ( r + 1 ) ∑ i = 1 r d [ i ] − ∑ i = 1 r i × d [ i ] res = \sum\limits_{i=1}^{r}\sum\limits_{j=1}^i d[j] = \sum\limits_{i=1}^{r} (r-i+1) \times d[i] = (r+1)\sum\limits_{i=1}^{r} d[i] - \sum\limits_{i=1}^{r}i\times d[i] res=i=1rj=1id[j]=i=1r(ri+1)×d[i]=(r+1)i=1rd[i]i=1ri×d[i] .

    于是 维护 d [ i ] d[i] d[i], i × d [ i ] i \times d[i] i×d[i]

  • 区间修改 ( + x ) (+x) (+x):
    d [ i ] d[i] d[i] 差分, l l l + x +x +x, r + 1 r+1 r+1 − x -x x .
    i × d [ i ] i \times d[i] i×d[i] 差分, l l l +   x × l +\ x\times l + x×l, r + 1 r+1 r+1 −   x × ( r + 1 ) - \ x \times (r+1)  x×(r+1) .


实 现 部 分 \color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register
typedef long long ll;

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 5e5 + 5;

int N;
int M;
int W;
int L;
int cnt;

ll Ans[maxn];

struct Sgment{ int x, l, r, flag, id; } A[maxn<<2];

bool cmp(Sgment a, Sgment b){ return a.x < b.x; }

struct Bit_Tree{

        int lim;
        ll d[maxn], d2[maxn];

        void Add(int k, ll x){
                for(reg int i = k; i <= lim; i += (i&-i)) d[i] += x, d2[i] += 1ll*x*k;
        }

        ll Ask(int k){
                if(k <= 0) return 0;
                ll s = 0;
                for(reg int i = k; i; i -= (i&-i)) s += (1ll*k+1)*d[i] - d2[i];
                return s;
        }

        void modify(const int &l, const int &r, const ll &x){ Add(l, x), Add(r+1, -x); }

        ll query(const int &l, const int &r){ return Ask(r) - Ask(l-1); }

} bit_t[2];

int main(){
        N = read(), M = read(), W = read(), L = read();
        for(reg int i = 1; i <= N; i ++){
                int x1 = read(), y1 = read(), x2 = read(), y2 = read();
                A[++ cnt] = (Sgment){ x1, y1+1, y2, 1, 0 };
                A[++ cnt] = (Sgment){ x2, y1+1, y2, -1, 0 };
        }
        for(reg int i = 1; i <= M; i ++){
                int x1 = read(), y1 = read(), x2 = read(), y2 = read();
                A[++ cnt] = (Sgment){ x1, y1+1, y2, -1, i };
                A[++ cnt] = (Sgment){ x2, y1+1, y2, 1, i };
        }
        bit_t[0].lim = bit_t[1].lim = L;
        std::sort(A+1, A+cnt+1, cmp);
        for(reg int i = 0, j = 1; i <= W; i ++){
                while(A[j].x == i){
                        if(!A[j].id){
                                bit_t[1].modify(A[j].l, A[j].r, 1ll*A[j].flag*i);
                                bit_t[0].modify(A[j].l, A[j].r, A[j].flag);
                        }else{
                                ll s1 = bit_t[1].query(A[j].l, A[j].r);
                                ll s2 = bit_t[0].query(A[j].l, A[j].r);
                                Ans[A[j].id] += 1ll*A[j].flag*(1ll*i*s2 - s1);
                        }
                        j ++;
                }
        }
        for(reg int i = 1; i <= M; i ++) printf("%lld\n", Ans[i]);
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值