ACM暑假集训日记 17.8.18 树状数组
来源:互联网 发布:中维网络监控 编辑:程序博客网 时间:2024/06/12 22:48
今天继续看了一下树状数组的博客,没有很多的新知识,主要是看了一个离线处理,其他的都是看过的知识点了,但是对于不同的题目使用不尽相同,感觉还是要多看一些题目才能真正的掌握树状数组
先说一下离线处理吧,有时候我们会遇到这样一种问题,给出一个序列,然后给出几个区间查询,求出给定区间内不同数值的和(如果一个数值在这个区间内多次出现也只算一次,不重复加),这时我们采取离线处理的方法,可以想到,在一个区间内,同一个数值只让他出现一次即可,那么我们一开始处理序列的时候,如果a[i]是第一次出现,那么加入树状数组,如果已经出现那么跳过,这样一来,对于任意SUM(R)(即区间[1,R])来说,都是满足要求的,做完1为起点区间的查询以后,我们进行[2,R]的查询,这时候,我们需要消除a[1]对后续的影响,使得我们这个序列好像就是从a[2]开始的,a[1]好像是不存在的,想要达到这个目的,我们需要ADD(1,-a[1])然后在a[1]值下一次出现的地方y位置进行ADD(y,a[1])。这样的话就比较明了了,
我们必须要进行的是按照各个区间的L值进行从小到大的排列,然后依次查询。
当我们查询玩[i,R]后,要进行的操作是
找到a[i]的值出现的下一个位置y(不存在的话是-1),执行ADD(i,-a[i]),ADD(y,a[i])
可以看出我们需要用数组next[i]=j记录a[i]出现的下一个位置j,还需要用hash[h]=i表示值为a[i]出现的第一个位置a[i];
HDU 3874 就是一个很经典的例子
点击打开原题
题意和思路都和上面叙述的差不多,直接发代码了
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define MAXN 50010#define MAXV 1000010#define MAXM 200010long long e[MAXN],ans[MAXM];int a[MAXN],t,n,m;int lowbit(int k){ return k&(-k);}long long SUM(int k){ long long re=0; while(k) { re+=e[k]; k-=lowbit(k); } return re;}void ADD(int k,int v){ while(k<MAXN) { e[k]+=v; k+=lowbit(k); }}struct nodenode{ int head[MAXV],next[MAXV]; void mem() { memset(head,-1,sizeof(head)); } void make(int i,int v) { next[i]=-1; if(head[v]==-1) head[v]=i; else { int j=head[v]; while(next[j]!=-1) j=next[j]; next[j]=i; } } int find(int i) { return next[i]; }}hhh;struct node{ int l,r,index; bool operator < (const node &b)const { return l<b.l; }}nodes[MAXM];int main(){ scanf("%d",&t); while(t--) { scanf("%d",&n); hhh.mem(); memset(e,0,sizeof(e)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(hhh.head[a[i]]==-1) ADD(i,a[i]); hhh.make(i,a[i]); } scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d%d",&nodes[i].l,&nodes[i].r); nodes[i].index=i; } sort(nodes+1,nodes+m+1); int j=1; for(int i=1;i<=n;i++) { while(nodes[j].l==i) { ans[nodes[j].index]=SUM(nodes[j].r); j++; } if(j>m)break; ADD(i,-a[i]); int next_ai=hhh.find(i); if(next_ai!=-1) ADD(next_ai,a[i]); } for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); }}
也看了几个树状数组+DP的题目,感觉关键点还是找到DP公式比较关键,
还有的一些题目不太容易能够想到使用树状数组,所以感觉还是要多花点时间练习练习才行。
- ACM暑假集训日记 17.8.18 树状数组
- ACM暑假集训日记 17.8.15 树状数组
- ACM暑假集训日记 17.8.16 树状数组
- 暑假集训日记--8.19--树状数组
- 暑假集训日记--8.21--树状数组
- 暑假集训日记--8.23--树状数组
- ACM暑假训练日记 17.8.17 树状数组
- ACM暑假训练日记 17.8.23 多维改段求点型树状数组
- ACM暑假集训日记 17.8.1
- ACM暑假集训日记 17.8.2
- ACM暑假集训日记 17.8.3
- ACM暑假集训日记 17.8.4
- ACM暑假集训日记 17.8.5
- ACM暑假集训日记 17.8.7
- ACM暑假集训日记 17.8.8
- ACM暑假集训日记 17.8.10
- ACM暑假集训日记 17.8.11
- ACM暑假集训日记 17.8.14
- oracle 表查询(经典例子)--2017-08-19
- 暑假总结第17天
- Opencv Sift算子特征提取与匹配
- Python:numpy中dot,outer,*用法
- 欢迎使用CSDN-markdown编辑器
- ACM暑假集训日记 17.8.18 树状数组
- 软件包管理:rpm和yum
- hdu 5862(离散化+树状数组)
- linux IPC --- 有名信号量详解
- Linux数据库(sqlite3)
- Ubuntu——将应用固定在任务栏
- 遗传算法
- ubuntu 安装nvidia
- Python日志8/18