二叉索引树,LA2191,LA5902,LA4329

利用了二进制,二分的思想的一个很巧妙的数据结构,一个lowbit(x):二进制表示下的最右边的一个1开始对应的数值。
那么如果一个节点的为x左孩子,父亲节点就是 x + lowbit(x),如果是右孩子,父亲节点是 x-lowbit(x);
图中白条部分就是辅助数组C对应的最底下的和。
1、那么一个前缀和有是怎样的呢?
就是从最底下开始,边往上走,边往左走。
2、修改单点呢?
从最底下开始,边往上走,边往下走。
LA2191:
题目链接:https://vjudge.net/contest/147973#problem/A
题意:
先给出一个数组,然后有两个操作
S x y 把第x个数改成y
M x y计算x~y个数的和
Source Code:
#include <bits/stdc++.h> using namespace std; inline int lowbit(int x)
{
return x&-x;
} struct FenwickTree
{
int n;
vector<int> C; void resize(int n)
{
this->n = n;
C.resize(n+);
}
void clear()
{
fill(C.begin(), C.end(), );
} // 计算A[1]+A[2]+...+A[x] (x<=n)
int sum(int x)
{
int ret = ;
while(x > )
{
ret += C[x];
x -= lowbit(x);
}
return ret;
} // A[x] += d (1<=x<=n)
void add(int x, int d)
{
while(x <= n)
{
C[x] += d;
x += lowbit(x);
}
}
}; FenwickTree f;
const int maxn = +;
int a[maxn]; int main()
{
// freopen("in.txt","r",stdin);
int n;
int cases = ;
while(scanf("%d",&n),n)
{
if(cases>) puts("");
printf("Case %d:\n",++cases);
f.resize(n);
f.clear();
for(int i=; i<=n; i++)
{
scanf("%d",&a[i]);
f.add(i,a[i]);
} char op[];
while(scanf("%s",op)!=EOF)
{
if(!strcmp(op,"END"))
break;
if(op[]=='M')
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",f.sum(y)-f.sum(x-));
}
if(op[]=='S')
{
int x,y;
scanf("%d%d",&x,&y);
int add = y - a[x];
a[x] = y;
f.add(x,add);
}
}
} return ;
}
LA5902:
题目链接:https://vjudge.net/contest/147973#problem/B
题意:
XXX喜欢看电影,他有好多好多的影碟,每个影碟都有个独立的编号。开始是从下往上影碟的顺序是n~1,他每次拿出影碟的时候,你需要输出压在该影碟上的有几个。(拿出后其他影碟顺序不变)看完影碟后,XXX会把影碟放在最上面。
分析:
把每个影碟放到一个考后的位置,这个位置有影碟,那么这里就是 1,否则是 0 ,每次询问,就是这个影碟所在的位置之前的前缀和,
把他放到前面去,当前位置置为 0 ,top 的位置 加 1,注意要记录每个影碟的所在位置。
Source Code:
#include <bits/stdc++.h> using namespace std; inline int lowbit(int x)
{
return x&-x;
} struct FenwickTree
{
int n;
vector<int> C; void resize(int n)
{
this->n = n;
C.resize(n);
}
void clear()
{
fill(C.begin(), C.end(), );
} // 计算A[1]+A[2]+...+A[x] (x<=n)
int sum(int x)
{
int ret = ;
while(x > )
{
ret += C[x];
x -= lowbit(x);
}
return ret;
} // A[x] += d (1<=x<=n)
void add(int x, int d)
{
while(x <= n)
{
C[x] += d;
x += lowbit(x);
}
}
}; FenwickTree f;
const int maxn = +;
int pos[maxn]; int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
scanf("%d",&t); while(t--)
{
int n,q;
scanf("%d%d",&n,&q);
f.resize(maxn*);
f.clear(); for(int i=; i<=n; i++)
{
f.add(maxn+i,);
pos[i] = maxn+i;
} int top = maxn;
while(q--)
{
int x;
scanf("%d",&x);
int tmp = pos[x];
if(q!=)
printf("%d ",f.sum(tmp-));
else printf("%d",f.sum(tmp-));
f.add(tmp,-);
f.add(top--,);
pos[x] = top + ;
}
puts("");
}
return ;
}
LA4329
题意:
一条大街上住着n个乒乓球爱好者,经常组织比赛。每个人都有一个技能值ai,每场比赛需要3个人:两名选手和一名裁判。规定裁判位置必须在两个选手的中间,而且技能值也必须在两个选手的中间,问一共能组织多少种比赛。
分析:
和上题类似,每个技能值有的话为 1 ,否则为 0 ,每一个点都可以做裁判,那么他能组织多少场比赛?
a1~ai-1 有 ci个比 ai 小,ai+1~an有di个比他小,乘法加法原理,ci(n-i-di) + di(i-ci-1)。
#include <bits/stdc++.h>
using namespace std;
inline int lowbit(int x) {
return x&-x;
}
struct FenwickTree {
int n;
vector<int> C;
void resize(int n) {
this->n = n;
C.resize(n);
}
void clear() {
fill(C.begin(),C.end(),);
}
//计算A[1] + A[2] + ... +A[n]
int sum(int x) {
int ret = ;
while(x>) {
ret +=C[x];
x -=lowbit(x);
}
return ret;
}
// A[x] +=d;
void add(int x,int d) {
while(x<=n) {
C[x] +=d;
x +=lowbit(x);
}
}
};
const int maxn = + ;
int n;
int a[maxn];
FenwickTree f;
int c[maxn],d[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int maxa = ;
scanf("%d",&n);
for(int i=;i<=n;i++) {
scanf("%d",&a[i]);
maxa = max(maxa,a[i]);
}
f.resize(maxa);
f.clear();
for(int i=;i<=n;i++) {
f.add(a[i],);
c[i] = f.sum(a[i]-);
}
f.clear();
for(int i=n;i>=;i--) {
f.add(a[i],);
d[i] = f.sum(a[i]-);
}
long long ans = ;
for(int i=;i<=n;i++) {
ans +=(long long)c[i]*(n-i-d[i]) + (long long)(i-c[i]-)*d[i];
}
printf("%lld\n",ans);
}
return ;
}
二叉索引树,LA2191,LA5902,LA4329的更多相关文章
- 【转载】区间信息的维护与查询(一)——二叉索引树(Fenwick树、树状数组)
在网上找到一篇非常不错的树状数组的博客,拿来转载,原文地址. 树状数组 最新看了一下区间的查询与修改的知识,最主要看到的是树状数组(BIT),以前感觉好高大上的东西,其实也不过就这么简单而已. 我们有 ...
- 二叉索引树BIT
定义 二叉索引树,binary index tree,又名树状数组,或Fenwick Tree,因为本算法由Fenwick创造. 对于数组A,定义Query(i,j) = Ai +Ai ...
- C++实用数据结构:二叉索引树
看下面这个问题(动态连续和查询): 有一个数组A(长度为n),要求进行两种操作: add(i,x):让Ai增大x: query(a,b):询问Aa+Aa+1+...+Ab的和: 若进行模拟,则每次qu ...
- POJ 3321 Apple Tree dfs+二叉索引树
题目:http://poj.org/problem?id=3321 动态更新某个元素,并且求和,显然是二叉索引树,但是节点的标号不连续,二叉索引树必须是连续的,所以需要转化成连续的,多叉树的形状已经建 ...
- NYOJ 116 士兵杀敌(二)(二叉索引树)
http://acm.nyist.net/JudgeOnline/problem.php?pid=116 题意: 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的 ...
- HDU 1166 敌兵布阵(线段树 or 二叉索引树)
http://acm.hdu.edu.cn/showproblem.php?pid=1166 题意:第一行一个整数T,表示有T组数据. 每组数据第一行一个正整数N(N<=50000),表示敌人有 ...
- 【树状数组(二叉索引树)】轻院热身—candy、NYOJ-116士兵杀敌(二)
[概念] 转载连接:树状数组 讲的挺好. 这两题非常的相似,查询区间的累加和.更新结点.Add(x,d) 与 Query(L,R) 的操作 [题目链接:candy] 唉,也是现在才发现这题用了这个知识 ...
- 树状数组(二叉索引树 BIT Fenwick树) *【一维基础模板】(查询区间和+修改更新)
刘汝佳:<训练指南>Page(194) #include <stdio.h> #include <string.h> #include <stdlib.h&g ...
- 1.红黑树和自平衡二叉(查找)树区别 2.红黑树与B树的区别
1.红黑树和自平衡二叉(查找)树区别 1.红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单. 2.平衡 ...
随机推荐
- 一些自己编写的简单的js
图片在窗口内弹来弹去的效果 <div class="FrontAdv_float01-default" style="position: absolute;z-in ...
- Linux进程间通信的几种方式
1.管道及有名管道(pipe & named pipe) pipe 用于亲缘关系的进程间通信,named pipe除了pipe的功能外,还可以进行无亲缘关系进程间的通信. 2.信号(Signa ...
- Java-IO中的节点流和处理流
理解好Java-IO中的节点流和处理流是理解Java输入.输出的关键基础,因此,了解节点流和处理流相关的知识点尤为重要. 1.定义 (1)节点流:可以从或向一个特定的地方(节点)读写数据.如FileR ...
- Fortran和C的编译器PGI部署
平台信息 Description: CentOS Linux release 7.6.1810 (Core) 安装步骤 获取PGCC:社区版是免费的,自带license.dat 解压下载的压缩包:ta ...
- python函数基础学习
函数的定义与调用: def 函数名(参数1,参数2): ‘’’函数注释’’’ print(‘函数体’) return 返回值 定 义:def关键字开关,空格之后接函数名和圆括号,最后冒号结尾 def ...
- http学习笔记(三):报文
三.报文 目录: 3.1方法 1.get 2.head 3.put 4.post 5.trace 6.options 7.delete 3.2状态码 ...
- pat1002. A+B for Polynomials (25)
1002. A+B for Polynomials (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue T ...
- js实现的省市县三级联动的最新源码
<!DOCTYPE html> <html> <head> <title>省市区三级联动</title> <!-- 直接使用QQ的省市 ...
- .NET Core 部署到CentOS–2.创建守护进程, 通过Nginx公网访问
继上一篇, 我们确定在内网可以通过 "http://localhost:5000",可以访问到站点后,接下来我们要配置"守护进程","Nginx公网8 ...
- 如何将运维的报警做成运营的报警--Java后端架构
转:http://mp.weixin.qq.com/s?__biz=MzI4OTU3ODk3NQ==&mid=2247483970&idx=1&sn=2a00acfb25f0c ...