【HDU No. 1166】 敌兵布阵
创始人
2024-03-03 13:24:04
0

【HDU No. 1166】 敌兵布阵

杭电 OJ 题目地址

在这里插入图片描述

【题意】

A国在海岸线沿直线布置了N 个工兵营地。C国通过先进的监测手段对A国每个工兵营地的人数都掌握得一清二楚。每个工兵营地的人数都可能发生变动,可能增加或减少若干人手。

【输入输出】

输入:

第1行包含一个整数T ,表示有T 组数据。每组数据的第1行都包含一个正整数N (N ≤50000),表示有N 个工兵营地。接下来有N 个正整数,第i 个正整数ai 代表第i 个工兵营地开始时有ai 个人(1≤ai ≤50)。再接下来每行都有一条命令,每组数据最多有40000条命令,命令有4种形式:①Add i j ,表示第i 个营地增加j 个人(j≤30);②Sub i j ,表示第i 个营地减少j 个人(j ≤30);③Query i j ,i ≤j ,表示查询第i ~j 个营地的总人数(int以内);④End,表示结束,在每组数据的最后出现。

命令中的i 和j 均为正整数。

输出:

对第i 组数据,首先单行输出“Case i:”,然后对每个Query都单行输出查询区间的总人数。

【样例】

在这里插入图片描述

【思路分析】

这道题包括点更新和区间查询,可以采用树状数组或者线段树解决。

【算法设计】

① 创建线段树,存储区间和。

② 点更新,查询到该点后进行点更新,返回时更新区间和。

③ 区间查询,首先查找该区间,然后返回区间和值。

创建线段树时可以采用存储区间信息和不存储区间信息两种方法,本题采用不存储区间信息的方法创建线段树,并对两种区间查询方法进行对比。

【创建线段树的两种方法】

创建线段树的方法不同,数据结构和区间查询时的参数也不同。

① 节点存储区间信息。每个节点都存储区间信息l 、r ,以及其他信息如最值或和值。在前面线段树的基本操作中就采用了这种方式,进行区间查询时只需3个参数:待查询区间L 、R 和当前节点的编号。

② 节点不存储区间信息。每个节点都不存储区间信息l、r ,用数组存储其他信息如最值或和值。进行区间查询时需要5个参数:待查询区间L 、R ;当前节点的l 、r ;当前节点编号rt 。节点不存储区间信息构建线段树的代码如下,区间查询的代码在后面给出。

#define lson l , m , rt << 1
#define rson m + 1, r, rt << 1 | 1void build(int l , int r , int rt){ // 构建线段树if(l == r){scanf("%d" , &sum[rt]);return;}int m = (l + r) >> 1;build(lson);build(rson);sum[rt] = sum[rt * 2] + sum[rt * 2 + 1]; // 更新区间和
}

【 区间查询的两种方法】

无论采用哪种方法创建线段树,都可以采用区间覆盖和区间相等两种方法进行区间查询。以节点不存储区间信息的5个参数区间和查询为例,3个参数类似。

① 区间覆盖。判断条件为覆盖时,查询区间无须改变,一直是[L , R ],累加左右两个区间查询的和值。

int query(int L,int R,int l,int r,int rt)//区间查询1
{if (L<=l&&r<=R)// 判断条件为覆盖,查询区间[L, R] 覆盖当前节点区间[l ,r]return sum[rt];int m=(l+r)>>1;int ret=0; // 定义变量,分两种情况累加 区间和( 或者求最值)if(L<=m) ret+=query(L,R,lson);if(R>m) ret+=query(L,R,rson);return ret; // 返回结果
}

② 区间相等。判断条件为相等且跨两个区间查询时,左右子树的查询范围分别变为[L , m ]、[m +1, R ]。

int query(int L,int R,int l,int r,int rt){//区间查询2if(L==l&&r==R)//判断条件为相等,查询区间[L, R] 等于当前节点区间[l ,r]return sum[rt];int m=(l+r)>>1;if(R<=m) // 分三种情况直接返回结果return query(L,R,lson);else if(L>m)return query(L,R,rson);else return query(L,m,lson)+query(m+1,R,rson); // 左右子树查询范围变为[L, m]、 [m + 1 , R]
}

【算法实现】

#include
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1const int maxn=55555;int sum[maxn<<2];void PushUP(int rt){//更新和值sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}void build(int l,int r,int rt){//构建线段树if(l==r){scanf("%d",&sum[rt]);return ;}int m=(l+r)>>1;build(lson);build(rson);PushUP(rt);
}void update(int p,int add,int l,int r,int rt){//单点更新if (l==r){sum[rt]+=add;return ;}int m=(l+r)>>1;if(p<=m) update(p,add,lson);else update(p,add,rson);PushUP(rt);
}int query(int L,int R,int l,int r,int rt){//区间查询2if(L==l&&r==R)//判断条件为相等return sum[rt];int m=(l+r)>>1;if(R<=m)return query(L,R,lson);else if(L>m)return query(L,R,rson);else return query(L,m,lson)+query(m+1,R,rson);
}int main(){int T,n;scanf("%d",&T);for (int cas=1;cas<=T;cas++){printf("Case %d:\n",cas);scanf("%d",&n);build(1,n,1);char op[10];while(scanf("%s",op)){if(op[0]=='E') break;int i,j;scanf("%d%d",&i,&j);if(op[0]=='Q') printf("%d\n",query(i,j,1,n,1));else if(op[0]=='S') update(i,-j,1,n,1);else update(i,j,1,n,1);}}return 0;
}

在这里插入图片描述

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...