bzoj2683:简单题(树状数组套CDQ分分治)

本文介绍了CDQ分治算法,这是一种离线分治方法,源自2008NOI金牌选手陈丹琦。通过CDQ分治可以解决离线操作问题,例如BZOJ P2683中的棋盘问题,通过排序、树状数组和分治思想来维护操作顺序和影响。当题目要求在线操作时,如增加异或操作,则需要使用其他数据结构,如KD-Tree。
摘要由CSDN通过智能技术生成

CDQ(陈丹琦)分治

CDQ显然是一个人的名字(2008NOI金牌选手陈丹琦) 这种离线的分治算法在算法界被称为"CDQ分治"。
 首先回忆一下归并排序的分治, 它的操作是将数组二分, 然后分别对左半部分和右半部分递归的用归并排序, 左右两部分都有序后再将两个部分合并成一个有序的数组, 这是大家都十分熟悉的分治.
 而CDQ(陈丹琦)分治的不同之处在于,每次划分后将左半部分对右半部分的贡献的累加, 递归的调用这个过程, 实现整体结果的计算。具体什么是前半部分对后半部分的贡献需要根据题意而定.
要用CDQ分治解决问题, 首先要求是题目支持离线操作,如果题目强制在线的话就不能用CDQ分治了,只能考虑用别的数据结构来维护
 所以CDQ分治的的主要步骤为
1.先对整体排序(按照第一维排序);
2.计算左半区间对右半区间的贡献;
3.撤销累加贡献时的操作;
4.二分的对左半部分和右半部分调用这个过程;

下面来看一个具体的例子来加深对CDQ分治的了解

BZOJ P2683 简单题

Description

你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
在这里插入图片描述

Sample Input

4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

Sample Output

3
5

根据题意,这题有两个要素:一个是x坐标, 一个是y坐标, 我们很容易想到第一维x直接排序, 第二维y用数据结构维护, 这里可以用树状数组(对于树状数组默认大家都会,在此不做过多介绍)维护好x和y的序列后,现在要解决的问题就是操作顺序如何划分:因为只有添加操作和查询操作按照一定的顺序进行分析才能得到正确的结果,每一次查询都需要确保前面的添加操作已经完成,否则可能得到的就是错误答案。那么如何维护操作的顺序呢?
 我们不妨添加一个维度(第三维:时间)。对每一个操作都记录下他的时间(或者说顺序)。这样就能区分哪些操作在哪些操作的前面了。如何维护第三维呢?这里我们就可以用CDQ分治来解决。
在运用CDQ分治前要搞清楚一个问题,在本题中,什么叫前半部分对后半部分的贡献呢? 记ADD操作为添加,Q操作为查询, 考虑这样一组操作 :ADD(3,3,1) Q(4,5) Q(2,5) ADD(1,2,1) 在这组操作中:

  1. ADD(3,3,1)可以对Q(4,5)的结果产生影响,但是却不能对Q(2,5)的结果产生影响, 因为根据题意, ( 2 , 5 ) (2,5) (2,5)对于现有的点 ( 3 , 3 ) (3,3) (3,3)不满足 ( 2 > = 3 ) (2 >= 3) (2>=3)
  2. ADD(1,2,1)不能对Q(4,5) 或Q(2,5)的结果产生影响, 因为此添加操作在上述查询操作之后

这就是CDQ分治中的更新前半部分对后半部分的影响, 对于x和y我们已经用排序和树状数组维护好了,只需要对第三维时间进行CDQ分治即可
下面附上代码:

/*
 * Copyright (c) 2019 Ng Kimbing, HNU, All rights reserved. May not be used, modified, or copied without permission.
 * @Author: Ng Kimbing, HNU.
 * @LastModified:2019-04-17 T 11:29:42.681 +08:00
 */


package ACMProblems.DivideAndConquer;

import java.util.Arrays;

import static ACMProblems.ACMIO.*;  // My IO

public class EasyProblem_2683 {
   
    static class Operation {
   
        int x;
        int y;
        int operationType;
        int n_thQuery;
        int timeLine;
        int value;

        Operation(int x, int y, int operationType, int n_thQuery, int timeLine, int value) {
   
            this.x = x;
            this.y = y;
            this.operationType = operationType;
            this.n_thQuery = n_thQuery
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值