2018SEERC Points and Rectangles (CDQ分治)

题目描述:

You have an empty infinite two-dimensional plane and qq queries. There are two types of queries:
&lt; &lt; 1 , x , y &gt; &gt; &lt;&lt; 1, x ,y&gt;&gt; <<1,x,y>>— add a point with the coordinates ( x , y ) (x, y) (x,y) to the plane.
&lt; &lt; 2 , x 1 , y 1 , x 2 , y 2 &gt; &gt; &lt;&lt;2 ,x1 ,y1 ,x2, y2&gt;&gt; <<2,x1,y1,x2,y2>> — add a rectangle whose lower left corner has the coordinates ( x 1 , y 1 ) (x1, y1) (x1,y1) and the upper right — ( x 2 , y 2 ) (x2, y2) (x2,y2). The area of this rectangle can be zero and a rectangle can degenerate into a point.

Rectangles and points may overlap, that is, there is not guarantee that the figures are distinct.

In addition, to fulfill these queries, after each of them, you need to print the number of pairs of rectangles and points, in which the point lies on the border or inside the rectangle.

题目大意:

二维平面上,两种操作:
1 x y:在(x,y)放一个点
2 x1,y1,x2,y2:放一个左下角为(x1,y1),右上角为(x2,y2)的矩阵。
每次操作之后要求出 所有矩阵包含的点的数目 的总和。
( x , y &lt; = 1 e 9 ) (x,y&lt;=1e9) (x,y<=1e9)

题解:

CDQ分治练习题
每次操作可以统计当前操作对局面的影响:
如果加入矩阵,则统计这个矩阵包含几个点。矩阵包含点可以看成是四个矩阵前缀和的询问。
如果加入点,则统计这个点被多少个矩阵包含。点 ( x p , y p ) (x_p,y_p) (xp,yp)被一个矩阵包含,则只有矩阵的左下角坐标满足条件 x &lt; x p , y &lt; y p x&lt;x_p,y&lt;y_p x<xp,y<yp,而其他三个点都不满足。
把点和矩阵分开讨论,矩阵是求小于等于的 ( x , y ) (x,y) (x,y)坐标,点是求小于的 ( x , y ) (x,y) (x,y)坐标。问题转换成求三维偏序。cdq分治求一下就可以了。

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) (x&(-x))
#define P pair<int, int>
using namespace std;
const int maxn = 5e5 + 50;
int a[maxn];
int ans[maxn];
void add(int i, int x){while(i < maxn) a[i] += x, i += lowbit(i);return;}
int qry(int i) {int res = 0;while(i) res += a[i], i -= lowbit(i);return res;}
struct node{
    int x, y, op, id;
    bool operator < (const node& a)const {return id < a.id;}
}e[maxn], temp[maxn];
vector<P> v;
void cdq1(int l, int r)//算点对矩阵的贡献(小于等于)
{
    if(r-l<=1) return;
    int mid = (r+l)>>1;
    cdq1(l, mid); cdq1(mid, r);
    int lp = l, rp = mid, o = 0;
    while(lp < mid && rp < r){
        if(e[lp].x <= e[rp].x){
            if(e[lp].op == 1){
                add(e[lp].y, 1);
                v.push_back(P(e[lp].y, 1));
            }
            temp[o++] = e[lp++];
        }
        else{
            if(e[rp].op == 2){
                ans[e[rp].id] += qry(e[rp].y);
            }
            else if(e[rp].op == 3) ans[e[rp].id] -= qry(e[rp].y);
            temp[o++] = e[rp++];
        }
    }
    while(lp < mid) temp[o++] = e[lp++];
    while(rp < r){
        if(e[rp].op == 2) ans[e[rp].id] += qry(e[rp].y);
        else if(e[rp].op == 3) ans[e[rp].id] -= qry(e[rp].y);
        temp[o++] = e[rp++];
    }
    for(int i = l; i <r; ++i) e[i] = temp[i - l];
    for(int i = 0; i < v.size(); ++i) add(v[i].first, -v[i].second);
    v.clear(); return;
}
void cdq2(int l, int r)//算矩阵对点的贡献(小于)
{
    if(r-l <= 1) return;
    int mid = (l+r)>>1;
    cdq2(l, mid); cdq2(mid, r);
    int lp = l, rp = mid, o = 0;
    while(lp < mid && rp < r){
        if(e[lp].x < e[rp].x){
            if(e[lp].op == 2){
                add(e[lp].y, 1); v.push_back(P(e[lp].y, 1));
            }
            else if(e[lp].op == 3){
                add(e[lp].y, -1); v.push_back(P(e[lp].y, -1));
            }
            temp[o++] = e[lp++];
        }
        else{
            if(e[rp].op == 1){
                ans[e[rp].id] += qry(e[rp].y-1);
            }
            temp[o++] = e[rp++];
        }
    }
    while(lp < mid) temp[o++] = e[lp++];//temp[o++] = e[lp++]写成 = temp[lp++],debug一小时
    while(rp < r){
        if(e[rp].op == 1) {
            ans[e[rp].id] += qry(e[rp].y - 1);
        }
        temp[o++] = e[rp++];
    }
    for(int i = l; i < r; ++i) e[i] = temp[i - l];
    for(int i = 0; i < v.size(); ++i) add(v[i].first, -v[i].second);
    v.clear(); return;
}
int cc[maxn*2];
int num = 0;
int main()
{
	int n;scanf("%d", &n);
	int idq = 0;
	for(int i = 0; i < n; ++i){
        int op;scanf("%d", &op);
        if(op == 1){
            scanf("%d%d", &e[idq].x, &e[idq].y);
            cc[++num] = e[idq].x; cc[++num] = e[idq].y;
            e[idq].op = 1; e[idq].id = i; idq++;
        }
        else{
            int x1, x2, y1, y2;
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            e[idq].op = 2, e[idq].x = x1-1, e[idq].y = y1 - 1, e[idq].id = i, idq++;
            e[idq].op = 2, e[idq].x = x2, e[idq].y = y2, e[idq].id = i, idq++;
            e[idq].op = 3, e[idq].x = x1-1, e[idq].y = y2, e[idq].id = i, idq++;
            e[idq].op = 3, e[idq].x = x2, e[idq].y = y1 - 1, e[idq].id = i, idq++;
            cc[++num] = x1-1, cc[++num] = y1 - 1, cc[++num] = x2, cc[++num] = y2;
        }
	}
	sort(cc+1, cc+num+1);
	num = unique(cc+1,cc+1+num) - cc - 1;
	for(int i = 0; i < idq; ++i){
        e[i].x = lower_bound(cc+1,cc+1+num,e[i].x) - cc;
        e[i].y = lower_bound(cc+1,cc+1+num,e[i].y) - cc;
	}
	cdq1(0, idq);
	sort(e, e+idq);
	cdq2(0, idq);
	ll sum = 0;
	for(int i = 0; i < n; ++i){
        sum += ans[i];
        printf("%lld\n", sum);
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值