首页 > 其他分享 >学习笔记 整体二分

学习笔记 整体二分

时间:2024-08-08 14:49:48浏览次数:10  
标签:二分 int rep mid 笔记 学习 read 答案

整体二分是一种离线算法
记 [l,r] 为答案的值域,[L,R] 为答案的定义域。(也就是说求答案时仅考虑下标在区间 [L,R] 内的操作和询问,这其中询问的答案在 [l,r] 内)

我们首先把所有操作 按时间顺序 存入数组中,然后开始分治。
在每一层分治中,利用数据结构(常见的是树状数组)统计当前查询的答案和 mid 之间的关系。
根据查询出来的答案和 mid 间的关系(小于等于 mid 和大于 mid)将当前处理的操作序列分为 q1 和 q2 两份,并分别递归处理。
当 l=r 时,找到答案,记录答案并返回即可。
需要注意的是,在整体二分过程中,若当前处理的值域为 [l,r],则此时最终答案范围不在 [l,r] 的询问会在其他时候处理。


整体二分要求

  • 询问的答案具有可二分性

  • 修改对判定答案的贡献互相独立,修改之间互不影响效果

  • 修改如果对判定答案有贡献,则贡献为一确定的与判定标准无关的值

  • 贡献满足交换律,结合律,具有可加性

  • 题目允许使用离线算法
    .




    例题:

[POI2011] MET-Meteors

题面翻译

Byteotian Interstellar Union

有 \(n​\) 个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为 \(m​\) 份(第 \(m​\) 份和第 \(1​\) 份相邻),第 \(i​\) 份上有第 \(a_i​\) 个国家的太空站。

这个星球经常会下陨石雨。BIU 已经预测了接下来 \(k\) 场陨石雨的情况。

BIU 的第 \(i\) 个成员国希望能够收集 \(p_i\) 单位的陨石样本。你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。

输入格式

第一行是两个数 \(n,m\)。

第二行有 \(m\) 个数,第 \(i\) 个数 \(o_i\) 表示第 \(i\) 段轨道上有第 \(o_i\) 个国家的太空站。

第三行有 \(n\) 个数,第 \(i\) 个数 \(p_i\) 表示第 \(i\) 个国家希望收集的陨石数量。

第四行有一个数 \(k\),表示 BIU 预测了接下来的 \(k\) 场陨石雨。 接下来 \(k\) 行,每行有三个数 \(l_i,r_i,a_i\) ,表示第 \(k\) 场陨石雨的发生地点在从 \(l_i\) 顺时针到 \(r_i\) 的区间中(如果 \(l_i \leq r_i\),则是 \(l_i, l_i + 1 \cdots, r_i\),否则就是 \(l_i, l_i + 1, \cdots m - 1, m, 1, 2, \cdots r_i\)),向区间中的每个太空站提供 \(a_i\) 单位的陨石样本。

输出格式

输出 \(n\) 行。第 \(i\) 行的数 \(w_i\) 表示第 \(i\) 个国家在第 \(w_i\) 波陨石雨之后能够收集到足够的陨石样本。如果到第 \(k\) 波结束后仍然收集不到,输出 NIE

样例 #1

样例输入 #1

3 5
1 3 2 1 3
10 5 7
3
4 2 4
1 3 1
3 5 2

样例输出 #1

3
NIE
1

首先 把询问离线下来。
在询问列表中二分。
把二分mid前的所有陨石雨都下一遍。
判断满足要求的国家空间站,将其放到l到mid中,剩下的不能满足的放在mid+r中。然后继续递归知道每个空间站在二分中找到结果。
因为有无解情况。
所以在最后多下一场覆盖所有空间站,雨量为inf的雨,在这场雨之后满足的就是无解情况。
举一个例子。
n = 6

 设每一场雨量都为1,#代表一场雨覆盖的范围
#####        *1
  #######    *2
  #####      *3
        ###  *4
4 6 2 1 3 5 //要求雨量
1 2 3 4 5 6 //下标
		

二分答案如图所示:
1 2 3 4
1 2|3 4
1|2|3|4

首先 1~4 mid = 2
将编号为1,2的两场雨下掉
发现下标为3 4的点已经满足了,划入1,2.其余点划入3,4.
在1,2点内。把编号为1的雨下掉,发现都没有满足。
所以下标为3,4的两个国家ans就为2.。。
如此类推。
code:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define int long long
#define inf 1000000000 
il int read() {
    re int x = 0, f = 1; re char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
    return x * f;
}
#define rep(i, s, t) for(re int i = s; i <= t; ++ i)
#define lb(x) (x)&(-(x))
#define maxn 300005
int n, m, ans[maxn], tr[maxn * 2], T;
struct ques {
	int l, r, a, id;
}e[maxn];
struct node {
	int ned, id;
}p[maxn], p1[maxn], p2[maxn];
vector<int> q[maxn];
il void add(int x, int v) {
	for(re int i = x; i <= 2 * m; i += lb(i)) tr[i] += v;
}
il int query(int x) {
	int ans = 0;
	for(re int i = x; i; i -= lb(i)) ans += tr[i];
	return ans;
}
il int Query(int x) {
	int ans = 0;
	for(re int i = 0; i < q[p[x].id].size(); ++ i) {
		ans += query(q[p[x].id][i]) + query(q[p[x].id][i] + m);
		if(ans >= p[x].ned) return ans;
	}
	return ans;
}
il void solve(int l, int r, int L, int R) {
	if(L > R) return;
	if(l == r) {
    	//如果二分到了终点,显然当前操作区间的答案都等于二分的答案
		rep(i, L, R) ans[p[i].id] = l;
		return;
	}
	int mid = (l + r) >> 1, cnt1 = 0, cnt2 = 0;
    //差分,假设[l, mid]的雨全部下下来
	rep(i, l, mid) add(e[i].l, e[i].a), add(e[i].r + 1, -e[i].a);
    //判断哪些答案大了,那些小了
	rep(i, L, R) {
		int temp = Query(i);
		if(temp >= p[i].ned) p1[++ cnt1] = p[i];
		else p[i].ned -= temp, p2[++ cnt2] = p[i];
	}
    //清空树状数组
	rep(i, l, mid) add(e[i].l, -e[i].a), add(e[i].r + 1, e[i].a);
    //归并排序
	rep(i, L, L + cnt1 - 1) p[i] = p1[i - L + 1];
	rep(i, L + cnt1, R) p[i] = p2[i - L - cnt1 + 1];
    //继续二分
	solve(l, mid, L, L + cnt1 - 1), solve(mid + 1, r, L + cnt1, R);
}
signed main() {
	n = read(), m = read();
	rep(i, 1, m) q[read()].push_back(i);
	rep(i, 1, n) p[i].ned = read(), p[i].id = i;
	T = read();
	rep(i, 1, T) {
		e[i].l = read(), e[i].r = read(), e[i].a = read(), e[i].id = i;
		if(e[i].r < e[i].l) e[i].r += m;
	}
	++ T, e[T].id = T, e[T].l = 1, e[T].r = 2 * m, e[T].a = inf;
	solve(1, T, 1, n);
	rep(i, 1, n) ans[i] == T ? puts("NIE") : printf("%lld\n", ans[i]);
	return 0;
}

标签:二分,int,rep,mid,笔记,学习,read,答案
From: https://www.cnblogs.com/Kang-shifu/p/18348952

相关文章

  • java笔记7
    12.异常什么是异常异常是指程序运行过程中发生的不正常情况,它中断了正常的指令流程。Java异常类结构图Java异常层次结构基于Throwable类,主要分为两大类:Error:表示编译时和系统错误(如OutOfMemoryError),通常是不可恢复的。Exception:表示程序运行中可以捕获并处理的异常。Erro......
  • AI入门之深度学习:基本概念篇
    1、什么是深度学习1.1、机器学习  图1:计算机有效工作的常用方法:程序员编写规则(程序),计算机遵循这些规则将输入数据转换为适当的答案。这一方法被称为符号主义人工智能,适合用来解决定义明确的逻辑问题,比如早期的PC小游戏:五子棋等,但是像图像分类、语音识别或自然语言翻译等......
  • IT领域新旅程:为高考新生打造的暑期学习路线图
    IT专业入门,高考假期预习指南七月来临,各省高考分数已揭榜完成。而高考的完结并不意味着学习的结束,而是新旅程的开始。对于有志于踏入IT领域的高考少年们,这个假期是开启探索IT世界的绝佳时机。作为该领域的前行者和经验前辈,你是否愿意为准新生们提供一份全面的学习路线图呢?快......
  • kubernetes笔记-4-kubernetes资源管理
    一、、kubernetes资源分类:工作负载、发现与负载均衡、配置与存储、集群、和元数据1、工作负载型资源分为:有状态和无状态两种类型;无状态:每个pod均可被其它其他同类所取代;有状态:有其独特性,必须单独标识和管理;ReplicaSet、Deployment负责无状态应用管理;StatefulSet负责有状态应用管......
  • 工作日志(记录自己的日常学习和腹诽)
    工作日志为了纪念自己的学习经历,也为了记录自己的试错过程创建于2024.6.11作者:刘佳琪[email protected]安装Keil5,破解软件需要防止被电脑病毒查杀功能删掉。24.06.18proteus8.13版本,51单片机串口无效,需替换MCS8051_7.DLL文件到MCS8051.DLL文件并改名为......
  • vb学习
    在VisualBasic(VB),数据类型用于定义变量可以存储的数据种类。以下是一些常用的VB数据类型:数值类型:Byte:无符号8位整数(0到255)。Integer:有符号16位整数(-32,768到32,767)。UInteger:无符号16位整数。Long:有符号32位整数(-2,147,483,648到2,147,483,647)。ULong:无符号32位整......
  • [rCore学习笔记 023]任务切换
    导读还是要先看官方手册.学过DMA的同志可能比较好理解,一句话,释放CPU总线:如果把应用程序执行的整个过程进行进一步分析,可以看到,当程序访问I/O外设或睡眠时,其实是不需要占用处理器的,于是我们可以把应用程序在不同时间段的执行过程分为两类,占用处理器执行有效任务的计算阶......
  • MySQL基础学习1
    标签(空格分隔):MySQLmysql常见的命令语句查看所有的数据库showdatabases;查看数据库:selectdatabase();打开指定的库use库名;查看当前库的所有表showtables;查看其他库的所有表showtablesform库名;创建表createtable表名(列名列类型,......
  • MySQL基础学习2
    标签(空格分隔):MySQL进阶五:分组查询语法:select分组函数,列(要求出现在groupby的后面)from表名【where筛选条件】groupby分组的列表【orderby子句】注意:查询列表必须特殊,groupby后面的字段特点:1、分组查询中的筛选条件分为两类|空格|数据源|位置|关键字|-|-|-|......
  • MySQL基础学习4
    标签(空格分隔):MySQLDML语言数据操作语言:插入:insert修改:update删除:delete一、插入语言插入方式1、语法:insertinto表名(列名,...)values(值1,...)插入的值的类型要与列的类型一致或兼容INSERTINTObeauty(id,name,sex,borndate,phone,photo,boyfriend_id)VALUES(13,'......