[CSP校内集训]矩形面积交(树状数组)

题意

给\(n\)个互不相交的矩形,再给\(m\)个询问,每次给一个矩形求它与这\(n\)个矩形的面积交

思路

自己写的太丑了导致DEBUG了一个半小时qwq

一对矩形的交可以拆分成二维前缀和形式下的矩形的交,于是变成判断16次矩形的交(不想画图...只想口胡)

这些矩形都有\(x_0=0,y_0=0\),即左下角为坐标原点,于是一个矩形可以只用右上角的坐标表示;

对于一个询问的矩形\((x,y)\)和另一个矩形\((x_i,y_i)\),它们的交为\(min(x,x_i)\times min(y,y_i)\)

对\(x\)排序,分类讨论\(y\leq y_i\)和\(y>y_i\),用树状数组维护即可

Code

#include<bits/stdc++.h>
#define N 500005
#define int ll
#define lowbit(x) ((x)&(-(x)))
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
int n,m,w,l,cnt0,cnt;
ll sum[N],sumy[N],sumx[N],c[N];
struct Matrix { int x,y,opt; } ma[N<<2];
struct Query { int x,y,id,opt; ll ans; } q[N<<2];

template <class T>
void read(T &x)
{
    char c; int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
void ad(int id,int opt,int x,int y)
{
    ++cnt;
    q[cnt].id=id; q[cnt].opt=opt;
    q[cnt].x=x; q[cnt].y=y;
}
void modify_1(int x,int val) { for(;x<N;x+=lowbit(x)) c[x]+=val; }
void modify_2(int x,ll val) { for(;x<N;x+=lowbit(x)) sum[x]+=val; }
void modify_3(int x,ll val) { for(;x<N;x+=lowbit(x)) sumy[x]+=val; }
void modify_4(int x,ll val) { for(;x<N;x+=lowbit(x)) sumx[x]+=val; }
ll query_1(int x) { ll ret=0; for(;x;x-=lowbit(x)) ret+=c[x]; return ret;}
ll query_2(int x) { ll ret=0; for(;x;x-=lowbit(x)) ret+=sum[x]; return ret;}
ll query_3(int x) { ll ret=0; for(;x;x-=lowbit(x)) ret+=sumy[x]; return ret;}
ll query_4(int x) { ll ret=0; for(;x;x-=lowbit(x)) ret+=sumx[x]; return ret;}
void update(Matrix a)//加入矩阵a
{
    modify_1(a.y,a.opt);
    modify_2(a.y,a.opt*(a.x*a.y));
    modify_3(a.y,a.opt*a.y);
    modify_4(a.y,a.opt*a.x);
}
bool cmp1(Matrix a,Matrix b) { return a.x<b.x; }
bool cmp2(Query a,Query b) { return a.x<b.x; }
bool cmp3(Query a,Query b) { return a.id<b.id; }
signed main()
{
    freopen("intersec.in","r",stdin);
    freopen("intersec.out","w",stdout);
    read(n);read(m);read(w);read(l);
    for(int i=1;i<=n;++i)
    {
        int x[2],y[2];
        read(x[0]);read(y[0]);
        read(x[1]);read(y[1]);
        ma[++cnt0]=(Matrix){x[1],y[1],1};
        ma[++cnt0]=(Matrix){x[0],y[1],-1};
        ma[++cnt0]=(Matrix){x[1],y[0],-1};
        ma[++cnt0]=(Matrix){x[0],y[0],1};
    }
    for(int i=1;i<=m;++i)
    {
        int x[2],y[2];
        read(x[0]);read(y[0]);
        read(x[1]);read(y[1]);
        ad(i,1,x[1],y[1]);
        ad(i,-1,x[0],y[1]);
        ad(i,-1,x[1],y[0]);
        ad(i,1,x[0],y[0]);
    }
    sort(ma+1,ma+cnt0+1,cmp1);
    sort(q+1,q+cnt+1,cmp2);
    int L=0;//加入了L个矩阵
    for(int i=1;i<=cnt;++i)//处理第i个询问矩阵
    {
        if(q[i].x==0||q[i].y==0) continue;
        while(L<cnt0&&ma[L+1].x<=q[i].x)
        {
            ++L;
            if(ma[L].x>0&&ma[L].y>0) update(ma[L]);
        }
        q[i].ans+=(query_2(q[i].y) + q[i].y*(query_4(N-1)-query_4(q[i].y)));
    }

    memset(c,0,sizeof(c));
    memset(sum,0,sizeof(sum));
    memset(sumx,0,sizeof(sumx));
    memset(sumy,0,sizeof(sumy));
    int R=cnt0+1;
    for(int i=cnt;i>=1;--i)
    {
        if(q[i].x==0||q[i].y==0) continue;
        while(R>1&&ma[R-1].x>q[i].x)
        {
            --R;
            if(ma[R].x>0&&ma[R].y>0) update(ma[R]);
        }
        q[i].ans+=q[i].x * (query_3(q[i].y) + (query_1(N-1)-query_1(q[i].y))*q[i].y);
    }
    sort(q+1,q+cnt+1,cmp3);
    for(int i=1;i<=cnt;i+=4)
    {
        ll ans=0;
        for(int j=0;j<4;++j) ans+=q[i+j].opt*q[i+j].ans;
        printf("%lld\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Chtholly/p/11782389.html

时间: 2024-10-21 03:52:02

[CSP校内集训]矩形面积交(树状数组)的相关文章

【LuoguP3038/[USACO11DEC]牧草种植Grass Planting】树链剖分+树状数组【树状数组的区间修改与区间查询】

模拟题,可以用树链剖分+线段树维护. 但是学了一个厉害的..树状数组的区间修改与区间查询.. 分割线里面的是转载的: -------------------------------------------------------------------------------- [ 3 ]  上面都不是重点--重点是树状数组的区间修改+区间查询 这个很好玩 其实也挺简单 首先依旧是引入delta数组 delta[i]表示区间 [i, n] 的共同增量 于是修改区间 [l, r] 时修改 delt

【bzoj5173】[Jsoi2014]矩形并 扫描线+二维树状数组区间修改区间查询

题目描述 JYY有N个平面坐标系中的矩形.每一个矩形的底边都平行于X轴,侧边平行于Y轴.第i个矩形的左下角坐标为(Xi,Yi),底边长为Ai,侧边长为Bi.现在JYY打算从这N个矩形中,随机选出两个不同的矩形,并计算它们的并的大小.JYY想知道,交的大小的期望是多少.换句话说即求在所有可能的选择中,两个矩形交的面积的平均大小是多大. 输入 输入一行包含一个正整数N. 接下来N行,每行4个整数,分别为Xi,Yi,Ai,Bi 2 < =  N < =  2*10^5, 0 < =  Xi,

USACO5.3 IDDFS_强连通_二维树状数组_斐蜀定理_矩形切割

启发式搜索 启发式搜索的主要思想是通过评价一个状态有"多好"来改进对于解的搜索. 方法#1:启发式剪枝 估价函数最简单最普通的用法是进行剪枝.假设有一个求最小代价的一个搜索,使用一个可行的估价函数.如果搜到当前状态时代价为A,这个状态的估价函数是B,那么从这个状态开始搜所能得到的最小代价是A+B.如果当前最优解是C满足C 方法#2:最佳优先搜索 最佳搜索可以看成贪心的深度优先搜索. 与一般搜索随意扩展后继节点不同,最优优先搜索按照估价函数所给的他们的"好坏"的顺序扩

【Hihocoder 1167】 高等理论计算机科学 (树链的交,线段树或树状数组维护区间和)

[题意] 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 少女幽香这几天正在学习高等理论计算机科学,然而她什么也没有学会,非常痛苦.所以她出去晃了一晃,做起了一些没什么意义的事情来放松自己.门前有一颗n个节点树,幽香发现这个树上有n个小精灵.然而这些小精灵都比较害羞,只会在一条特定的路径上活动.第i个小精灵会在ai到bi的路径上活动.两个小精灵是朋友,当且仅当它们的路径是有公共点的.于是幽香想要知道,有多少对小精灵a和b,a和b是朋友呢?其中a不等于b,a,b和b,

[扫描线+树状数组]解决矩形包含点的问题

今天做到第二题,大部分的思路都理解了之后最后剩下一个问题 zzx:“然后扫描线+树状数组搞一下就好了” 看到这两个算法就产生了一种我肯定会的错觉... 然后后来发现并不会的时候很惭愧... 然后十分感谢YDC,在之前完全陌生的情况下 我去问这样一个问题 超级超级超级耐心地给我解答  我问着每一个他们看起来显然的具体处理方法 突然发现真的像张老师说的:“你普及升提高的这条路没有怎么走,中间那块知识是空着的啊” 今天才切实体会到...但是或许正是这样今天学到这样的一个东西更让我觉得开心吧 树状数组解

[BASIC-18] 矩形面积交

基础练习 矩形面积交 时间限制:1.0s   内存限制:512.0MB 问题描述 平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴.对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积. 输入格式 输入仅包含两行,每行描述一个矩形. 在每行中,给出矩形的一对相对顶点的坐标,每个点的坐标都用两个绝对值不超过10^7的实数表示. 输出格式 输出仅包含一个实数,为交的面积,保留到小数后两位. 样例输入 1 1 3 3 2 2 4 4 样例输出 1.00 分析: 1.需要注

[BZOJ 4418][Shoi2013]扇形面积并(树状数组+二分)

Description 给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖. Solution 打开发现是计算几何还以为是看错题号了QwQ 其实就是遇到一条开始的边+1,遇到一条结束的边-1,a1>a2的话就再加上一个完整的圆 计算每一部分只需要找到第cnt-k+1大的半径,在树状数组上二分就好了 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #inc

蓝桥杯_基础练习《矩形面积交---26》

/* 基础练习 矩形面积交 问题描述 平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴.对于每个矩形,我们 给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积. 输入格式 输入仅包含两行,每行描述一个矩形. 在每行中,给出矩形的一对相对顶点的坐标,每个点的坐标都用两个绝对值不超过 10^7的实数表示. 输出格式 输出仅包含一个实数,为交的面积,保留到小数后两位. 样例输入 1 1 3 3 2 2 4 4 样例输出 1.00 */ //矩形的相交面积. #include<stdio.

基础训练 矩形面积交

矩形面积交 #include<iostream> #include<iomanip> using namespace std; int main(){ double m1, n1, m2, n2, a1, b1, a2, b2, d1=0, d2=0; cin>>m1>>n1>>m2>>n2>>a1>>b1>>a2>>b2; if(m1>m2) swap(m1, m2); if(n