POJ 3109 Inner Vertices 离散化+树状数组

一、题目大意

围棋棋盘,如果某个坐标上下左右的四个方向都存在棋子,那么ans+1,根据输入的棋子数量,求出ans的数量。

二、解题思路

题目中有说到如果程序不会结束,那么输出-1,这其实是无源之水,根本不会发生。

我们可以一列一列的循环,然后针对列建立一个树状数组(线段树也行,树状数组更快)

坐标比较大,需要离散化(离散化就是把有效坐标排好序去重放在数组里,然后用原坐标对应数字再数组元素的顺序来替换掉原坐标的算法,可以参阅《挑战程序设计》第三章-常用技巧精选,或者可以参考鄙人AOJ0531的拙作题解)本题目每个输入的棋子x和y是有效坐标,其余坐标均无效,因为没有棋子的行或列一定无法让ans+1。

之后根据列来排序,列一样的,就根据行来排序(pair默认的就行,first列,second行)

然后记录下每一行的最后一个棋子的坐标(可以定一个数组,初值设置1或0,循环一次所有的棋子,更新到每一行的最大列即可)

然后,同时记录一个bool型的标记数组,来代表某一行是否前面已经有个棋子,如下图

循环每一列的时候,把当前元素和当前列上一个元素之间的元素集体+1(树状数组操作)update(上一个元素的列+1,当前元素列-1,1)这里需要判断下上一个的列+1和当前列-1的大小,如果大于等于那就不要更新了

同时遇到每一行第一个棋子时,要把这一行标记上,然后这一行的位置更新到0(更新到0是因为这一行之前左边没有棋子,如果左边没有棋子,那么这些+1的情况,即便上下有子也不应该记录到答案里,为的就是防止下图中红色箭头的位置被错误记录了),这样下次再碰到这一行的棋子,就可以代表两者之间的部分位置可以加到答案里。

然后更新到每一行最后一列的时候(这里可以通过之前记录的行最大列的数组来判断是不是最后一列),如果这一行之前没有被标记过,即这一行的最后一个棋子左边没有棋子,那么这一行+1的那些坐标不算数,上下有子,右边也有,但是左边没有那就不行,直接continue。

如果这一行标记过,那那表左边有棋子,同时循环到的这一行的最后一个棋子是它右边的,然后更新树状数组时的区间边界是它上下的,那么树状数组求出这一行的数量,要加到ans里,我这个思路就是如下图所示,每一列右边的一些数子,就是遇到走过某一列的时候树状数组渲染到正常的样子(非树形求和的那种),然后红色的箭头的就代表走到某一行最后一列了增加ans,

表达的不清晰,见谅!

三、代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
P num[100010];
ll bit0[131080], bit1[131080], ans;
int x[100010], y[100010], xLen, yLen, n, n_, maxCol[100010];
bool activeRow[100010];
void input()
{for (int i = 1; i <= n_; i++){scanf("%d%d", &num[i].first, &num[i].second);x[i] = num[i].first;y[i] = num[i].second;activeRow[i] = false;maxCol[i] = 1;}sort(x + 1, x + (1 + n_));sort(y + 1, y + (1 + n_));
}
void compress()
{xLen = 1;yLen = 1;for (int i = 2; i <= n_; i++){if (x[xLen] != x[i]){x[++xLen] = x[i];}if (y[yLen] != y[i]){y[++yLen] = y[i];}}for (int i = 1; i <= n_; i++){num[i].first = lower_bound(x + 1, x + (xLen + 1), num[i].first) - x;num[i].second = lower_bound(y + 1, y + (yLen + 1), num[i].second) - y;if (maxCol[num[i].second] < num[i].first){maxCol[num[i].second] = num[i].first;}}
}
void init()
{n = 131072;for (int i = 0; i <= n; i++){bit0[i] = 0LL;bit1[i] = 0LL;}
}
void updateBit0(int r, ll v)
{if (r <= 0){return;}for (int i = r; i <= n; i = i + (i & (-i))){bit0[i] = bit0[i] + v;}
}
void updateBit1(int r, ll v)
{if (r <= 0){return;}for (int i = r; i <= n; i = i + (i & (-i))){bit1[i] = bit1[i] + v;}
}
ll queryBit0(int r)
{ll sum = 0LL;for (int i = r; i > 0; i = i - (i & (-i))){sum = sum + bit0[i];}return sum;
}
ll queryBit1(int r)
{ll sum = 0LL;for (int i = r; i > 0; i = i - (i & (-i))){sum = sum + bit1[i];}return sum;
}
void update(int l, int r, ll v)
{updateBit0(l, (-1LL) * v * ((ll)(l - 1)));updateBit0(r + 1, v * ((ll)r));updateBit1(l, v);updateBit1(r + 1, (-1LL) * v);
}
ll query(int l, int r)
{ll allAmt = queryBit0(r);ll allAdd = queryBit1(r) * ((ll)r);ll leftAmt = queryBit0(l - 1);ll leftAdd = queryBit1(l - 1) * ((ll)(l - 1));return (allAmt + allAdd - leftAmt - leftAdd);
}
void solve()
{sort(num + 1, num + (1 + n_));ans = 0LL;for (int i = 1; i <= n_; i++){if (i > 1 && num[i - 1].first == num[i].first && (num[i - 1].second + 1) < num[i].second){update(num[i - 1].second + 1, num[i].second - 1, 1LL);}if (maxCol[num[i].second] == num[i].first && !activeRow[num[i].second]){continue;}if (maxCol[num[i].second] == num[i].first && activeRow[num[i].second]){ans = ans + query(num[i].second, num[i].second);}if (!activeRow[num[i].second]){ll oldVal = query(num[i].second, num[i].second);update(num[i].second, num[i].second, (-1LL) * oldVal);activeRow[num[i].second] = true;}}
}
int main()
{while (~scanf("%d", &n_)){input();compress();init();solve();ans = ans + ((ll)n_);printf("%lld\n", ans);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/93287.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

altera FPGA 程序固化命令

altera FPGA 程序固化命令 一、命令解析 1&#xff09;sof文件转为flash文件的命令&#xff1a; qsys_sdram.sof为sof文件名称&#xff0c;hwimage.flash为生成的flash名称&#xff0c;针对不同的工程只需要更改这两个地方就可以 sof2flash --inputqsys_sdram.sof --outputh…

力扣第239题 c++滑动窗口经典题 单调队列

题目 239. 滑动窗口最大值 困难 提示 队列 数组 滑动窗口 单调队列 堆(优先队列) 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的…

【爬虫】用wget命令爬虫的简易教程

文章目录 1. 获取登录的请求2. 用postman模拟登录请求3. 用wget模拟登录请求并保存cookie4. 开始爬取网站5. 查看爬取结果6. 网站爬虫简易教程 爬取需要登录的网站的资源 背景&#xff1a;对于一些网站需要使用用户名和密码登录并且使用了https&#xff0c;我们如果不通过凭证将…

数据库表操作详解

在数据库管理中,表操作是最基础也最常用的一项功能。不论是临时存储一些数据,还是通过派生表进行复杂的查询,表操作的灵活性和多样性都使其在数据库中发挥着重要的作用。 本文将详细解析数据库中常见的表操作,包括临时表、派生表以及与视图、子查询的比较。我们将使用游戏…

Flutter开发环境的配置

2023-10最新版本 flutter SDK版本下载地址 https://flutter.cn/docs/development/tools/sdk/releases gradle各版本快速下载地址 https://blog.csdn.net/ii950606/article/details/109105402 JAVA SDK下载地址 https://www.oracle.com/java/technologies/downloads/#java…

代码随想录算法训练营第五十六天 | 1143. 最长公共子序列 1035.不相交的线 53. 最大子数组和

1. 最长公共子序列 1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 最长公共子数组必须连续&#xff0c;所以一旦元素不相等&#xff0c;当前的最长公共长度不能由前面得来&#xff0c;只能为0 而最长公共子序列&#xff0c;可以断开&#xff0c;所以不相等时…

从0开始python学习-27.selenium 简单登录页面脚本

url https://test.com.cn/login driver.get(url)# 获取登录页面需要输入账号密码进行模拟登录操作 user driver.find_element(By.XPATH,//*[id"username"]).send_keys(username) pwd driver.find_element(By.XPATH,//*[id"selfpwd"]).send_keys(123456)…

pytorch模型量化和移植安卓详细教程

十一下雨,在家撸模型,希望对pytorch模型进行轻量化,间断摸索了几天,效果不错,做个总结分享出来。 量化是一种常见的技术,人们使用它来使模型在推断时运行更快,具有更低的内存占用和更低的功耗,而无需更改模型架构。在这篇博客文章中,我们将简要介绍量化是什么以及如何…

【leetocde】128. 最长连续序列

给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&#xff1a; 输入&#xff1a;nums [100,4,200,1,3,2] 输出&#xff1a;4 …

win10系统任务栏图标变成白色的解决办法

我平时都是用滴答清单进行管理这个自己的日程代办的&#xff0c;但是今天打开的时候发现这个快捷方式突然变成纯白色的了&#xff0c;重启电脑之后&#xff0c;这个图标的样式仍然没有变化。上网查找解决办法之后&#xff0c;终于搞好了&#xff0c;于是就有了下面的教程。 为什…

大数据Flink(九十五):DML:Window TopN

文章目录 DML:Window TopN DML:Window TopN Window TopN 定义(支持 Streaming):Window TopN 是一种特殊的 TopN,它的返回结果是每一个窗口内的 N 个最小值或者最大值。 应用场景

数据结构—归并排序-C语言实现

引言&#xff1a;归并排序跟快速排序一样&#xff0c;都运用到了分治的算法&#xff0c;但是归并排序是一种稳定的算法&#xff0c;同时也具备高效&#xff0c;其时间复杂度为O(N*logN) 算法图解&#xff1a; 然后开始归并&#xff1a; 就是这个思想&#xff0c;拆成最小子问题…

数据结构与算法----递归

1、迷宫回溯问题 package com.yhb.code.datastructer.recursion&#xffe5;5;public class MiGong {public static void main(String[] args) {// 先创建一个二维数组&#xff0c;模拟迷宫// 地图int[][] map new int[8][7];// 使用1 表示墙// 上下全部置为1for (int i 0; i…

BASH shell脚本篇4——函数

这篇文章介绍下BASH shell中的函数。之前有介绍过shell的其它命令&#xff0c;请参考&#xff1a; BASH shell脚本篇1——基本命令 BASH shell脚本篇2——条件命令 BASH shell脚本篇3——字符串处理 函数是代码重用的最重要方式。Bash函数可以定义为一组命令&#xff0c;在b…

华为数通方向HCIP-DataCom H12-831题库(单选题:161-180)

第161题 某台路由器Router LSA如图所示,下列说法中错误的是? A、本路由器已建立邻接关系 B、本路由器为DR C、本路由支持外部路由引入 D、本路由器的Router ID为10.0.12.1 答案: B 解析: 一类LSA的在transnet网络中link id值为DR的route id ,但Link id的地址不是10.0.12.…

前端设计跨异步处理手段

简单描述下笔者所了解的单bit和多bit信号跨时钟域处理的常见手段。 单bit信号跨时钟域处理手段 电平信号&#xff1a;可以直接打拍处理&#xff1b;脉冲信号&#xff08;原始脉宽需保持至少2个DST时钟宽度&#xff09;&#xff1a;可以直接打拍处理&#xff0c;对同步后脉宽不…

asp.net core mvc Razor +dapper 增删改查,分页(保姆教程)

说明&#xff1a;本demo使用sqlserver数据库&#xff0c;dapper orm框架 完成一张学生信息表的增删改查&#xff0c;前端部分使用的是Razor视图&#xff0c; Linq分页 HtmlHelper。&#xff08;代码随便写的&#xff0c;具体可以自己优化&#xff09; //实现效果如下&#xff0…

介绍如何在Go中使用字符串

字符串是一个或多个字符(字母、数字、符号)的序列&#xff0c;可以是常量或变量。字符串由Unicode组成&#xff0c;是不可变的序列&#xff0c;这意味着它们是不变的。 因为文本是我们日常生活中使用的一种常见数据形式&#xff0c;所以字符串数据类型是编程中非常重要的组成部…

【Vue3】动态 class 类

如果你想在 Vue.js 中动态设置元素的 class 类名&#xff0c;你可以使用以下两种主要方式&#xff1a; 绑定一个动态的 class 对象&#xff1a;你可以使用 v-bind 或简写的 : 来绑定一个包含类名的对象&#xff0c;其中类名的键是类名字符串&#xff0c;值是一个布尔值或计算属…

管理经济学基本概念(二): 规模经济、需求曲线、供给曲线等

1、关键术语 1.1、边际报酬递减规律 边际报酬递减规律是指随着产出量的扩大&#xff0c;边际生产率(与增量投入要素相联系的增量产出量)最终会下降。 递增的边际生产率意味着边际成本递增。 递增的边际成本最终导致平均成本递增。 1.2、规模经济 (1) 如果长期平均成本相对…