树状数组题目详解 HDU 1166 HDU 1541

2024-02-14 14:18

本文主要是介绍树状数组题目详解 HDU 1166 HDU 1541,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

再次复习树状数组

这里写图片描述

上规律

c1 = a1;
c2 = a1 + a2;
c3 = a3;
c4 = a1 + a2 + a3 + a4;
c5 = a5;
………………
c16 = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16;

树状数组各元素表示的位数

cn = (n - a ^ k + 1) + ………………………… + an

代码版

    for (k = 1; k <= n; k++)for (l = k - lowbit(k) + 1; l <= k; l++)c[k] += b[l];

移位公式

int lowbit (int a)
{return a & (-a);
}

求和公式

int sum (int c[], int n)
{sum = 0;while(n > 0){sum += c[n]n -= lowbit(n);}
}

改变某一个变量公式

int change (int i, int x) // i表示更改的位置, x表示改为的数。
{while(i <= n){c[i] += x;i += lowbit(i);}
}

下面上题 HDU 1166(模板题)

敌兵布阵

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K
(Java/Others) Total Submission(s): 63224 Accepted Submission(s):
26668

Problem Description
C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:”你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:”我知错了。。。”但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的.

Input 第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式: (1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30) (2)Sub i
j ,i和j为正整数,表示第i个营地减少j个人(j不超过30); (3)Query i j
,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数; (4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令

Output 对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。

Sample Input 1 10 1 2 3 4 5 6 7 8 9 10 Query 1 3 Add 3 6 Query 2 7 Sub
10 2 Add 6 3 Query 3 10 End

Sample Output Case 1: 6 33 59

分析

首先简单来看这是一个很简单的累加求和的问题 但是过多的数据会使题目超时

当累加的时候有少量的数据改变的时候不需要重新累加 这时候就需要树状数组

当某个数据发生改变的时候树状数组只需要改变大于这个数最近的2的级数的数组 效率为logN

具体方法看复习

核心代码

计算初始的C数组:
for(i = 1; i <= n; i++)for(l = i - lowbit(i) + 1; l <= i;l++)c[i] += b[l];
前n项求和
int sum2 (int c[], int n)
{int sum = 0;while(n >0){sum += a[n];k -= lowbit(k);}
}
更新数组
void add(int i, int x, int c[])
{while(i < n){c[i] += x;i += lowbit(i);}
}

全部代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int lowbit(int a);
int sum2(int a[], int k);
void add(int i, int x, int c[]);
int n;
int b[100000];
int c[100000];
char d[10];
int main(void)
{int i, j, k, l, a, change1, change2, sum, v;while (scanf_s("%d", &a) != EOF){for (i = 1; i <= a; i++){memset(b, 0, sizeof(b)); memset(c, 0, sizeof(c)); scanf_s("%d", &n);for (j = 1; j <= n; j++)scanf_s("%d", &b[j]);for (k = 1; k <= n; k++)for (l = k - lowbit(k) + 1; l <= k; l++)c[k] += b[l];printf("Case %d:\n", i);getchar();scanf_s("%s", d, 10);while (d[0] != 'E'){scanf_s("%d %d", &change1, &change2);if (d[0] == 'Q'){sum = 0; v = change1 - 1;sum = sum2(c, change2) - sum2(c, v);//printf("%d %d  ", sum2(c, v), sum2(c, change2));printf("%d\n", sum);}else if (d[0] == 'A'){add(change1, change2, c);}else{add(change1, -(change2), c);}getchar();scanf_s("%s", d, 10);}}}return 0;
}int lowbit(int a)
{return a & (-a);
}int sum2(int a[], int k)
{int sum = 0;while (k > 0){sum += a[k];k -= lowbit(k);}return sum;
}void add(int i, int x, int c[])
{while (i <= n){c[i] += x;i += lowbit(i);}
}

HDU 1541

上题目

Stars Time Limit: 2000/1000 MS (Java/Others) Memory Limit:
65536/32768 K (Java/Others) Total Submission(s): 6737 Accepted
Submission(s): 2691

Problem Description Astronomers often examine star maps where stars
are represented by points on a plane and each star has Cartesian
coordinates. Let the level of a star be an amount of the stars that
are not higher and not to the right of the given star. Astronomers
want to know the distribution of the levels of the stars.

For example, look at the map shown on the figure above. Level of the
star number 5 is equal to 3 (it’s formed by three stars with a numbers
1, 2 and 4). And the levels of the stars numbered by 2 and 4 are 1. At
this map there are only one star of the level 0, two stars of the
level 1, one star of the level 2, and one star of the level 3.

You are to write a program that will count the amounts of the stars of
each level on a given map.

Input The first line of the input file contains a number of stars N
(1<=N<=15000). The following N lines describe coordinates of stars
(two integers X and Y per line separated by a space, 0<=X,Y<=32000).
There can be only one star at one point of the plane. Stars are listed
in ascending order of Y coordinate. Stars with equal Y coordinates are
listed in ascending order of X coordinate.

Output The output should contain N lines, one number per line. The
first line contains amount of stars of the level 0, the second does
amount of stars of the level 1 and so on, the last line contains
amount of stars of the level N-1.

Sample Input 5 1 1 5 1 7 1 3 3 5 5

Sample Output 1 2 1 1 0

翻译

我这弱菜的英语 - -

在 笛卡尔坐标系上有一张星空图。有N颗星 图中的每一颗星都用X,Y坐标表示。

每一颗星的亮度等于它左下角的星的个数

输出1 至 N - 1亮度的星的个数 每个一行

解析

我这弱菜的水平刚开始真没看出来这是一个树状数组的题目

其实从题目给的条件中也可以看出题目说了是从小到大排出X坐标优先

可以看成给出的一个暗示 可以通过树状数组来表示变化

下面我们来想象一下树状数组:

在读入第n个数据时,实际上就是求之前读入的数的X坐标小于第N个数的个数

因为题目给出的数字是默认排好序 x优先的 所以在之前的数不会有Y坐标大于第N个数的

同样因为要频繁的更改数组的第X项并改变前N项的和 所以优先考虑树状数组

伪码解析

从1到N循环读入数据(X0, Y0)用树状数组来计算前X0项的和计入数组 lignt[]中第X0项更新加一继续循环……
从1 到 n - 1 输出light[]数组

完全代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;const int maxn = 32050;
int  bit[maxn];
int  level[maxn];
int  n;int lowbit(int x)    //sum lowbit add 为树状数组模板代码 直接调用
{return x & (-x); //等价于x&(-x)
}void add(int x, int val)   //用树状数组对后面节点更新
{while (x<maxn){bit[x] += val;x += lowbit(x);}
}int sum(int x)
{int rank = 0;   //rank代表星星的等级,即它的左下角有的星星个数while (x>0){rank += bit[x];x -= lowbit(x);}return rank;
}int main()
{int   x, y;while (scanf_s("%d", &n) != EOF){memset(bit, 0, sizeof(bit));//清空数组memset(level, 0, sizeof(level));for (int i = 0; i < n; i++){scanf_s("%d%d", &x, &y);level[sum(++x)]++;  // sum函数计算出前x项和  也就是星的亮度add(x, 1);//更新数组}for (int i = 0; i<n; i++)printf("%d\n", level[i]);}return 0;
}

这篇关于树状数组题目详解 HDU 1166 HDU 1541的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/708720

相关文章

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

MySQL中的锁机制详解之全局锁,表级锁,行级锁

《MySQL中的锁机制详解之全局锁,表级锁,行级锁》MySQL锁机制通过全局、表级、行级锁控制并发,保障数据一致性与隔离性,全局锁适用于全库备份,表级锁适合读多写少场景,行级锁(InnoDB)实现高并... 目录一、锁机制基础:从并发问题到锁分类1.1 并发访问的三大问题1.2 锁的核心作用1.3 锁粒度分

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

MySQL count()聚合函数详解

《MySQLcount()聚合函数详解》MySQL中的COUNT()函数,它是SQL中最常用的聚合函数之一,用于计算表中符合特定条件的行数,本文给大家介绍MySQLcount()聚合函数,感兴趣的朋... 目录核心功能语法形式重要特性与行为如何选择使用哪种形式?总结深入剖析一下 mysql 中的 COUNT

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁