牛客网 暑期ACM多校训练营(第二场)J.farm-STL(vector)+二维树状数组区间更新、单点查询 or 大暴力?
开心.jpg
J.farm
先解释一下题意,题意就是一个n*m的矩形区域,每个点代表一个植物,然后不同的植物对应不同的适合的肥料k,如果植物被撒上不适合的肥料就会死掉。然后题目将每个点适合的肥料种类(不同的数字代表不同的种类)给出(最多n*m种肥料),然后T次操作,每次操作都是把以(x1,y1)为左上角,以(x2,y2)为右下角确定的矩形区域撒上种类为k的肥料,问T次操作后,死掉了多少植物。
这个题可以是个经典的二维树状数组的题目,通过二维树状数组维护区间,以及各种神奇操作过了这道题。
这道题有三种姿势可以过。
1)通过二维树状数组维护区间,通过hash随机化,使得点增加的数为初始存入的值的倍数,eg:8=4+4而不是8=2+6,最后直接取模初始值,不是倍数的就说明发生了变化。
2)通过二维树状数组维护变化的区间,然后vector保存不同种类的点的坐标,然后遍历所有种类。
3)大暴力,通过前缀和,变化过的点,下次就不再进行操作,一个点最多暴力两次,具体的不清楚什么姿势过的。
我是用第二种思路写的。
感觉vector真的是个好东西,通过vector把种类划分,就可以很轻松的解决种类划分问题。
二维树状通过四个点维护区间,和差分数组一样都是维护前缀和,本来还想用差分数组乱搞试试,好像没必要,因为这两个东西都是通过L,R左右两个边界维护前缀和,在L处+value,在R处-value,然后最后遍历一遍就可以得到区间的前缀和。具体有关树状数组和差分数组的问题,百度找度娘。
写这个题的思路就是通过一个vector将适合该种类i的点的坐标存起来。然后T次操作,再通过一个vector将撒上种类为k的区间的两个点的坐标存起来。将撒上肥料的区间对应的二维树状数组进行更新操作,每操作一个区间就将该区间的树状数组进行更新。T次操作后,每个点被操作过几次就可以通过树状数组查询出来。
然后遍历1到n*m种肥料,对于每一种肥料,把撒过该种肥料的区间取消标记,然后查询适合该种肥料的点,如果该点对应的树状数组里存的值不为0,说明有其他种类的肥料撒过该点,这个点的植物就死了,计数。然后再把取消的该点的标记变回去,这样不影响其他种类的点。
具体的操作都在代码里写了注释。
对于遍历1到n*m种肥料的时候,通过auto po:points[i]就可以很简洁的遍历vector,这个东西就类似于vector<int>::iterator it,it=points[i].begin();it!=points[i].end();it++;具体的自行百度,反正这个东西就可以把代码变的简洁好看一点。关于vector以及auto,贴几个博客链接:
就这些,贴代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdlib>
#include<cctype>
using namespace std;
const int maxn=1e6+;
const int inf=0x3f3f3f3f;
#define pii pair<int,int> vector<vector<int> >tree;
int n,m; void init()
{
tree.resize(n+);
for(int i=;i<=n;i++){
tree[i].resize(m+);
}
for(int i=;i<=n;i++){
for(int j=;j<=m;j++)
tree[i][j]=;
}
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int y,int val)
{
for(int i=x;i<=n;i+=lowbit(i)){
for(int j=y;j<=m;j+=lowbit(j)){
tree[i][j]+=val;
}
}
}
int query(int x,int y)
{
int ans=;
for(int i=x;i>;i-=lowbit(i)){
for(int j=y;j>;j-=lowbit(j)){
ans+=tree[i][j];
}
}
return ans;
}
void change(int x1,int y1,int x2,int y2,int val)
{
add(x1,y1,val);
add(x1,y2+,-val);
add(x2+,y1,-val);
add(x2+,y2+,val);
}
template <class T>
inline void scan_d(T &ret)
{
char c;
ret = ;
while ((c = getchar()) < '' || c > '');
while (c >= '' && c <= '')
{
ret = ret * + (c - ''), c = getchar();
}
}
vector<pii>points[maxn];
vector<pair<pii,pii> >area[maxn];
int main()
{
int t;
scan_d(n);scan_d(m);scan_d(t);
init();
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
int kind;
scan_d(kind);
points[kind].push_back({i,j});//points记录种类为kind的点的坐标
}
}
while(t--){
int x1,y1,x2,y2,k;
scan_d(x1);scan_d(y1);scan_d(x2);scan_d(y2);scan_d(k);
area[k].push_back({{x1,y1},{x2,y2}});//将修改为k的区间保存
change(x1,y1,x2,y2,);//将修改过的区间存到树状数组里进行维护,每修改过一次就赋值+1
}
int ans=;
for(int i=; i<=n*m; i++){//遍历
for(auto ar:area[i]){
int x1=ar.first.first;
int y1=ar.first.second;
int x2=ar.second.first;
int y2=ar.second.second;
change(x1,y1,x2,y2,-);//将更改为k的区间还原
}
for(auto po:points[i]){
int xx=po.first,yy=po.second;
int cnt=query(xx,yy);
if(cnt!=)ans++;//如果查询出来的值不为0,说明对于适合种类为i的点来说,有其他种类更改过,所以这个点的要死掉了
}
for(auto ar:area[i]){//将还原的种类i更改过的区间再变成修改过的样子,这样才不会影响适合其他种类的点
int x1=ar.first.first;
int y1=ar.first.second;
int x2=ar.second.first;
int y2=ar.second.second;
change(x1,y1,x2,y2,);
}
}
printf("%d\n",ans);
return ;
}
就这样,很认真的写的代码和博客。
牛客网 暑期ACM多校训练营(第二场)J.farm-STL(vector)+二维树状数组区间更新、单点查询 or 大暴力?的更多相关文章
- 牛客网暑期ACM多校训练营 第九场
HPrefix Sum study from : https://blog.csdn.net/mitsuha_/article/details/81774727 k较小.分离x和k. 另外的可能:求a ...
- 牛客网暑期ACM多校训练营(第四场):A Ternary String(欧拉降幂)
链接:牛客网暑期ACM多校训练营(第四场):A Ternary String 题意:给出一段数列 s,只包含 0.1.2 三种数.每秒在每个 2 后面会插入一个 1 ,每个 1 后面会插入一个 0,之 ...
- 牛客网暑期ACM多校训练营(第五场):F - take
链接:牛客网暑期ACM多校训练营(第五场):F - take 题意: Kanade有n个盒子,第i个盒子有p [i]概率有一个d [i]大小的钻石. 起初,Kanade有一颗0号钻石.她将从第1到第n ...
- 牛客网 暑期ACM多校训练营(第二场)A.run-动态规划 or 递推?
牛客网暑期ACM多校训练营(第二场) 水博客. A.run 题意就是一个人一秒可以走1步或者跑K步,不能连续跑2秒,他从0开始移动,移动到[L,R]的某一点就可以结束.问一共有多少种移动的方式. 个人 ...
- 牛客网 暑期ACM多校训练营(第一场)A.Monotonic Matrix-矩阵转化为格子路径的非降路径计数,Lindström-Gessel-Viennot引理-组合数学
牛客网暑期ACM多校训练营(第一场) A.Monotonic Matrix 这个题就是给你一个n*m的矩阵,往里面填{0,1,2}这三种数,要求是Ai,j⩽Ai+1,j,Ai,j⩽Ai,j+1 ,问你 ...
- 牛客网暑期ACM多校训练营(第三场)H Diff-prime Pairs (贡献)
牛客网暑期ACM多校训练营(第三场)H Diff-prime Pairs (贡献) 链接:https://ac.nowcoder.com/acm/contest/141/H来源:牛客网 Eddy ha ...
- 2018牛客网暑期ACM多校训练营(第二场)I- car ( 思维)
2018牛客网暑期ACM多校训练营(第二场)I- car 链接:https://ac.nowcoder.com/acm/contest/140/I来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 ...
- Different Integers 牛客网暑期ACM多校训练营(第一场) J 离线+线状数组或者主席树
Given a sequence of integers a1, a2, ..., an and q pairs of integers (l 1, r1), (l2, r2), ..., (lq, ...
- 牛客网暑期ACM多校训练营(第七场)Bit Compression
链接:https://www.nowcoder.com/acm/contest/145/C 来源:牛客网 题目描述 A binary string s of length N = 2n is give ...
随机推荐
- WPFDataGrid可以编辑某列Bug,困惑已久
这个问题困扰了好几天,最近在做DataGrid编辑列,有一个添加按钮,当我点击添加按钮的时候自动生成一行,并别生成序列号,然后按回车键完成添加,但是有一个问题就是:当我点击完添加按钮以后,然后继续添加 ...
- 【Pascal's Triangle II 】cpp
题目: Given an index k, return the kth row of the Pascal's triangle. For example, given k = 3,Return [ ...
- navmesh自动寻路
一个导航网格(也就是Navmesh)是世界几何体简化的表示法,被游戏代理用于在世界中进行导航.通常,代理(agent )有一个目标,或一个目的地,它试图找到一个路径,然后沿路径导航到达目标.这个过程被 ...
- Python全栈工程师(包、模块 的导入)
ParisGabriel 每天坚持手写 一天一篇 决定坚持几年 为了梦想 为了信仰 Python人工智能从入门到精通 $ pip3 install tenso ...
- NodeJs06 高并发
高并发架构 在业务的最初期,由于业务和用户的体量比较小,可能采用单机就足够了.随着业务的增长,用户量和并发请求量都会不断上升.当增长到一定的瓶颈的时候,系统能否抗住压力,就需要采取一些方案了.这就是著 ...
- iptables的配置文件/etc/sysconfig/iptables不存在 linux防火墙开关命令
某linux服务器,使用 cat /etc/sysconfig/iptables命令时, 找不到文件. 1. service iptables status 使用该命令检查状态 如果之前找不到配置文件 ...
- 500 OOPS: vsftpd: refusing to run with writable anonymous root
500 OOPS: vsftpd: refusing to run with writable anonymous root 以下就是解决的三个步骤,其中第一步,是我一直没有搞明白的,也是其中的重点: ...
- htmlagilitypack解析html
这是个很好的的东西,以前做Html解析都是在用htmlparser,用的虽然顺手,但解析速度较慢,碰巧今天找到了这个,就拿过来试,一切出乎意料,非常爽,推荐给各位使用. 下面是一些简单的使用技巧,希望 ...
- SPOJ - BALNUM Balanced Numbers
题意: 求出所给范围内满足其数位上的奇数出现偶数次,数位上的偶数出现奇数次(或不出现)的数的个数. 思路: 对于0 ~ 9 每个数有3种情况. 1.没出现过 2.出现奇数次 3.出现偶数次 那么就可以 ...
- [bzoj3456] 城市规划 [递推+多项式求逆]
题面 bzoj权限题面 离线题面 思路 orz Miskcoo ! 先考虑怎么算这个图的数量 设$f(i)$表示$i$个点的联通有标号无向图个数,$g(i)$表示$n$个点的有标号无向图个数(可以不连 ...