二维数点问题

二维数点问题:

给定平面上的$n$个点$(x_i,y_i)$, 权值$f(x_i,y_i)$, $m$次矩形查询$\sum\limits_{\substack{a \le i \le b \\ c \le j \le d}}f(i,j)$

以下记$S(a,b)=\sum\limits_{\substack{i \le a \\ j \le b}}f(i,j)$

一般解法: 

先将矩形查询拆成四个二维前缀和S(b,d)-S(a-1,d)-S(b,c-1)+S(a-1,c-1), 从而转化为偏序问题.

对于静态的二维数点, 等价于二维偏序问题, 离线可以用树状数组, 在线可以主席树.

对于动态的二维数点, 等价于三维偏序问题, 离线可以用CDQ套树状数组, 在线可以树套树.

 

 

例1. luogu P1972 [SDOI2009]HH的项链

大意: 给定$n$元素序列$a$, $m$个询问, 求区间$[l,r]$内不同元素的个数.

静态二维数点板子题, 可以转化为求$\sum\limits_{\substack{l \le i \le r \\ 0 \le pre[i] \le l-1}}1$, 其中$pre[x]$为$a[x]$上一次出现位置

我们取坐标轴为序列的下标和pre数组, $a$中每个元素看成点$(i,pre[i])$, 那么就是一个标准的二维数点问题, 先考虑离线做法.

1. 离线做法一般是先将所有点和询问按一个坐标轴排序, 然后用树状数组算贡献.

(1)按序列下标排序.

点已经有序, 对于询问$[l,r]$, 拆成前缀形式S(r,l-1)-S(l-1,l-1)再排序, 用树状数组维护pre的贡献

#include <iostream>
#include <algorithm>
#include <cstdio>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;

const int N = 1e6+10;
int n, m, cnt;
int a[N], pre[N], vis[N], ans[N];
struct _ {
    int type,x,y,id;
    bool operator < (const _ & rhs) const {
        return x<rhs.x;
    }
} e[N];

int c[N];
void add(int x) {
    for (++x; x<=n+1; x+=x&-x) ++c[x];
}
int query(int x) {
    int r = 0;
    for (++x; x; x^=x&-x) r+=c[x];
    return r;
}
int main() {
    scanf("%d", &n);
    REP(i,1,n) { 
        scanf("%d", a+i);
        pre[i] = vis[a[i]];
        vis[a[i]] = i;
    }
    scanf("%d", &m);
    REP(i,1,m) { 
        int l, r;
        scanf("%d%d", &l, &r);
        e[++cnt] = {-1,l-1,l-1,i};
        e[++cnt] = {
    
    1,r,l-1,i};
    }
    sort(e+1,e+1+cnt);
    int now = 1;
    REP(i,1,cnt) {
        while (now<=e[i].x) add(pre[now++]);
        ans[e[i].id]+=e[i].type*query(e[i].y);
    }
    REP(i,1,m) printf("%d\n",ans[i]);
}
View Code

(2)按pre排序.

#include <iostream>
#include <algorithm>
#include <cstdio>
#define REP(i,a,n) for(int i=a;i<=n;++i)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值