首先我们都了解过树状数组这一短小精悍的利器,知道它和差分以及推公式的简单结合。但很显然问题不会那么裸
下面我们将讨论两道关于树状数组的简单应用题,看看具体包装下的树状数组题目

一.   楼兰图腾    acwing241.

题目描述:在完成了分配任务之后,西部 314314 来到了楼兰古城的西部。

相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(V),一个部落崇拜铁锹(),他们分别用 V 和  的形状来代表各自部落的图腾。

西部 314314 在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了 nn 个点,经测量发现这 nn 个点的水平位置和竖直位置是两两不同的。

西部 314314 认为这幅壁画所包含的信息与这 nn 个点的相对位置有关,因此不妨设坐标分别为 (1,y1),(2,y2),…,(n,yn)(1,y1),(2,y2),…,(n,yn),其中 y1∼yny1∼yn 是 11 到 nn 的一个排列。

西部 314314 打算研究这幅壁画中包含着多少个图腾。

如果三个点 (i,yi),(j,yj),(k,yk)(i,yi),(j,yj),(k,yk) 满足 1≤i<j<k≤n1≤i<j<k≤n 且 yi>yj,yj<ykyi>yj,yj<yk,则称这三个点构成 V 图腾;

如果三个点 (i,yi),(j,yj),(k,yk)(i,yi),(j,yj),(k,yk) 满足 1≤i<j<k≤n1≤i<j<k≤n 且 yi<yj,yj>ykyi<yj,yj>yk,则称这三个点构成  图腾;

西部 314314 想知道,这 nn 个点中两个部落图腾的数目。

因此,你需要编写一个程序来求出 V 的个数和  的个数。

输入格式

第一行一个数 nn。

第二行是 nn 个数,分别代表 y1,y2,…,yny1,y2,…,yn。

输出格式

两个数,中间用空格隔开,依次为 V 的个数和  的个数。

数据范围

对于所有数据,n≤200000n≤200000,且输出答案不会超过 int64int64。
y1∼yny1∼yn 是 11 到 nn 的一个排列。

输入样例:

5
1 5 3 2 4

输出样例:

3 4

思路与思考过程:
首先是1e5,所以应该是一个线性或者logn的问题

首先本题可以抽象后就是,对于任意一个位置的数字,统计他前面有几个数字比他大,后面有几个数字比他大,根据乘法原理,可以很容易求出题目要求的个数问题,但本题的关键在于能想到用树状数组来做,首先本题和裸的树状数组不同点在于他不是统计区间和,而是统计区间中总共有几个数字出现了(是一个排列,不用考虑数字重复问题),同时是单点修改,动态的区间查询,只满足这两个基本操作就可以了从这一点出发就不难想到要使用树状数组来做。

下面是代码,思路比较不容易想出,代码就没那么难了,关键在于思路的抽象
乘法原理+树状数组

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+10;
int tr[N];
LL great[N],lower[N];
LL n,res1,res2;
int q[N];
int lowbit(int x)
{return x&-x;
}
void add(int x,int c)
{for(int i=x;i<=n;i+=lowbit(i))tr[i]+=c;
}
int sum(int x)
{int res=0;for(int i=x;i;i-=lowbit(i))res+=tr[i];return res;
}
int main()
{cin>>n;for(int i=1;i<=n;i++){int x;scanf("%d",&x);q[i]=x;great[i]=sum(n)-sum(x);//x+1  --  n;lower[i]=sum(x-1);add(x,1);}memset(tr,0,sizeof tr);for(int i=n;i>=1;i--){great[i]=great[i]*(LL)(sum(n)-sum(q[i]));lower[i]=lower[i]*(LL)(sum(q[i]-1));add(q[i],1);}for(int i=1;i<=n;i++)res1+=great[i],res2+=lower[i];cout<<res1<<" "<<res2;}

小结:这里其实是树状数组的一个基本应用就是离线的处理每一个数字前面比他大的数字有多少个的问题,树状数组是把这个问题转换成了区间求和和单点更新。

二.  逆序对 洛谷p1908

思路:这道题数字在1e9,个数只有5e5,所以需要先离散化预处理再跑一遍树状数组求任意一个数字左边比他大的数字有几个就ok了。

知识铺垫:自己之前离散化也没学过(太蒟蒻了),所以先分享一道关于离散化模板的题目,很多时候树状数组和线段树的题目都要用到离散化。

AcWing 802. 区间和

假定有一个无限长的数轴,数轴上每个坐标上的数都是 0 。

现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。

接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r][l,r] 之间的所有数的和。

输入格式

第一行包含两个整数 n和 m。

接下来 n 行,每行包含两个整数 x和 c。

再接下来 m 行,每行包含两个整数 l 和 r。

输出格式

共 m 行,每行输出一个询问中所求的区间内数字和。

数据范围

−109≤x≤109−109≤x≤109,
1≤n,m≤1051≤n,m≤105,
−109≤l≤r≤109−109≤l≤r≤109,
−10000≤c≤10000−10000≤c≤10000

输入样例:

3 3
1 2
3 6
7 5
1 3
4 6
7 8

输出样例:

8
0
5

没什么花哨的玩意,就是一个离散化的基础模板,但是很多题目都是好多个模板拼接起来组成的
所以要重视基础的作用
下面是代码:

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
typedef pair<int,int>PII;
vector<int>alls;
vector<PII>add,query;
int n,m;
int a[N],s[N];
int find(int x)
{int l=0,r=alls.size()-1;while(l<r){int mid=l+r>>1;if(alls[mid]>=x)r=mid;else l=mid+1;}return l+1;
}
int main()
{cin>>n>>m;while(n--){int x,y;scanf("%d%d",&x,&y);add.push_back({x,y});alls.push_back(x);}while(m--){int l,r;scanf("%d%d",&l,&r);query.push_back({l,r});alls.push_back(l);alls.push_back(r);}sort(alls.begin(),alls.end());alls.erase(unique(alls.begin(),alls.end()),alls.end());for(auto item:add)a[find(item.first)]+=item.second;for(int i=1;i<=alls.size();i++)s[i]=s[i-1]+a[i];for(auto item:query)printf("%d\n",s[find(item.second)]-s[find(item.first)-1]);}

有了离散化,这个逆序对的题目就迎刃而解了。
注意答案要用longlong来存(自己一发就错在这上面了。。。)

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
typedef long long LL;
int tr[N];
int n;
vector<int>alls;
int q[N];
int lowbit(int x)
{return x&-x;
}
void add(int x,int c)
{for(int i=x;i<=alls.size();i+=lowbit(i))tr[i]+=c;
}
int sum(int x)
{int res=0;for(int i=x;i;i-=lowbit(i))res+=tr[i];return res;
}
int find(int x)
{int l=0,r=alls.size()-1;while(l<r){int mid=l+r>>1;if(alls[mid]>=x)r=mid;else l=mid+1;}return l+1;
}
int main()
{cin>>n;for(int i=1;i<=n;i++)scanf("%d",&q[i]),alls.push_back(q[i]);sort(alls.begin(),alls.end());alls.erase(unique(alls.begin(),alls.end()),alls.end());LL res=0;for(int i=1;i<=n;i++){int st=find(q[i]);//    printf("hehe\n");q[i]=st;res+=sum(alls.size())-sum(st);add(st,1);}cout<<res;}

参考资料:acwing算法基础课,算法提高课

7.25 树状数组的简单应用题相关推荐

  1. 树状数组(简单介绍)

    树状数组解决的问题: 假如有这样一种情景,先输入一个长度为n的数组,然后我们有如下两种操作: 输入一个数m,输出数组中下标1~m的前缀和 对某个指定下标的数进行值的修改 多次执行上述两种操作: 常规方 ...

  2. HDU 1166 敌兵布阵【树状数组】

    用树状数组很简单,太晚了,贴下代码睡觉去... 另,研究线段树的时候,发现网上流传着有几种不同的线段树,最正宗的是以单位区间为单位,只能处理线段:另外还有几种叶子结点是点的,这种也可以用来处理点,所以 ...

  3. 校门外的树——树状数组+区间修改

    校门外的树 [题目分析]题目描述的是一种区间修改,看起来好像要用线段树.但是对于这种区间内部没有差别并且查询的是区间内的类别的问题,是可以转化为树状数组进行的.毕竟树状数组更加简单. 我们的关注点应该 ...

  4. 数据结构--树状数组

    文章目录 1. 树状数组 2. 单点修改 3. 区间修改 4. 完整代码 5. 参考文献 1. 树状数组 类似数据结构:线段树(Segment Tree) 树状数组 跟 线段树 的区别: 树状数组能做 ...

  5. php 树状数组公式,PY个树状数组

    树状数组比较简单,于是就挑它下手了... 于是生活终于也对咱下手了... 要讲的就两个东西,一个是开数组,全局变量写最前面,数组是这么开的: f=[0 for i in range(500005)] ...

  6. Codeforces Round #439 (Div. 2) E. The Untended Antiquity 二维线段树||二维树状数组

    http://codeforces.com/contest/869/problem/E 题意:n*m的矩阵,q次操作,三种类型 类型1:给指定矩阵加上围栏 类型2:给指定矩阵去掉围栏 类型3:查询两点 ...

  7. 树状数组(单点修改,区间修改等)

    前言:上次练习树状数组的专题还是半年前,练了练就过了,后来学了线段树,觉得树状数组这啥啊,线段树不香吗,就再也没管过树状数组了.直到几天前被树状数组血虐了,急忙爬回来补树状数组.(事实证明学的越少,越 ...

  8. 洛谷 P5057 [CQOI2006]简单题(树状数组)

    嗯... 题目链接:https://www.luogu.org/problem/P5057 首先发现这道题中只有0和1,所以肯定与二进制有关.然后发现这道题需要支持区间更改和单点查询操作,所以首先想到 ...

  9. CF56E Domino Principle 树状数组 + 简单dp

    一个比较简单的题,但是我还是没做出来(哭. 很容易想到从后往前做,所以我们可以维护一个dp数组f,f(i)表示到第i个牌倒下能达到的最远距离. f直接倒着跑,每次取[x,x+h−1][x,x+h-1] ...

最新文章

  1. 求求你别再用offset和limit分页了
  2. 【解析】工业机器人中的各类传感器技术应用
  3. git 设置别名大全( git alias)
  4. SQL Server性能调优之执行计划深度剖析 第二节 执行计划第一次实践
  5. C语言文件读写(3)-二进制文件读写操作
  6. NYOJ 26 孪生素数问题
  7. 1^2+2^2+……+n^2的公式证明
  8. conda pip安装在哪里_Python环境篇-Minicondaamp;Pip使用汇总
  9. (转)Win10下PostgreSQL10与PostGIS安装
  10. 脚本_vnote同步到hexo步骤[博]
  11. 黑苹果 电脑关机是因为发生了问题_【电脑常识】常见的电脑误区,你中了几点?...
  12. Dism++ 一款传说中的系统工具,使用简介
  13. 计算机算法需要什么数学知识,计算机编程算法和数学有什么关系?
  14. 温湿度传感器的原理与特点
  15. 论文写作学习心得体会
  16. Python 操作 Excel 表格
  17. 拇指玩安装器提示“存储卡空间不足”的解决办法
  18. java map存储对象_java-在ConcurrentHashMap中存储复杂对象
  19. DSSD : Deconvolutional Single Shot Detector论文阅读笔记
  20. CPU占用过高问题排查

热门文章

  1. 最详细的WLAN无线综合实验
  2. 拿不到offer全额退款|第四期人工智能NLP/CV课 培训招生
  3. innerHTML与innerText区别
  4. 一级计算机考试题库25套答案,13年大学计算机一级试题有答案(25套).doc
  5. Java自动生成背景透明的印章或签名
  6. 计算机考试中上网题怎么保存,计算机网页题怎么做 一级计算机考试上网题怎么做...
  7. java遍历是什么意思_详解java中多种通用遍历方式
  8. 【分区数据恢复】分区意外丢失,如何恢复数据?
  9. 灵魂相似的人,总会相逢
  10. 关于计算机的名言英语作文,英语作文万能名言【三篇】