欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 锐评 > 蓝桥杯备赛 Day15 树形数据结构

蓝桥杯备赛 Day15 树形数据结构

2025/5/16 6:31:50 来源:https://blog.csdn.net/2301_80044595/article/details/146840026  浏览:    关键词:蓝桥杯备赛 Day15 树形数据结构

树状数组基础

解决问题

1.树状数组可以解决“动态修改动态查询区间和”的问题(前缀和是多次修改完多次查询),不过一般解决单点修改+区间查询问题
2.树状数组先要了解lowbit操作,这是一种二进制操作,取一个数字二进制表达中最低位的1以及后面所有的0,例如:
lowbit(4)=lowbit(100)=100=4
lowbit(6)=lowbit(110)=10=2
lowbit函数代码:

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

3.树状数组即一个数组int t[N],表示为 t [ i ] = ∑ j = i − l o w b i t ( i ) + 1 i a [ i ] t[i]=\sum_{j=i-lowbit(i)+1}^{i} a[i] t[i]=j=ilowbit(i)+1ia[i]
即维护一个长为lowbit(x)的[x-lowbit[x]+1,x]的区间和
4.单点修改函数,如下图,修改a[3]+k,就是t[3]+k,t[4]+k,t[8]+k,而3+lowbit(3)=4,4+lowbit(4)=8,直到小于等于n

//给a[k]增加x
void update(int k,int x){for(int i=k;i<=n;i+=lowbit(i)){t[i]+=x;}
}

5.区间查询函数:如下图,查询区间[3,7],即获得[1,7]-[1,2],而[1,7]=t[7]+t[6]+t[4],而7-lowbit(7)=6,6-lowbit(6)=4,直到为0(不能等于0,不然死循环,所以树状数组开始不能为0)

//获取[1,k]的区间和
void getprefix(int k){int res=0;for(int i=k;i>0;i-=lowbit(i)){res+=t[i];}return res;
}

![[树状数组.png]]

殷老师排队

学习:
(1)记得输入a[i]的时候**update(i,a[i])初始化t数组**
(2)单点修改不仅要调用update函数,还有记得修改a[i]数组
代码:

#include <bits/stdc++.h>using namespace std;
const int N=1e5+10;
int a[N],t[N],n,m;int lowbit(int x){return x & (-x);
}//第x个学生的魅力值增加k 
void update(int x,int k){for(int i=x;i<=n;i+=lowbit(i)){t[i]+=k;}
} //获取[1,x]的学生的魅力值和
int getprefix(int x){int res=0;for(int i=x;i>0;i-=lowbit(i)){res+=t[i];}return res;
} int main(){ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];update(i,a[i]); //初始化t数组 }for(int i=1;i<=m;i++){int op;cin>>op;if(op==1){int x,z;cin>>x>>z;	update(x,z-a[x]);a[x]=z; //记得更新a[x] }else{int x;cin>>x;cout<<(2*x-n)*a[x]+getprefix(n)-2*getprefix(x)<<endl;}}return 0;
}
拼十字

学习:
(1)此题暴力筛选会超时,充要条件是矩形 1 的长度严格大于矩形 2 的长度并且矩形 1 的宽度严格小于矩形 2 的宽度,就可以给结构体矩形首先按长度降序排列(如果长度一样则按宽度降序排列,保证不会选这两个),然后问题就转化为求宽度小于当前矩形的宽度的矩形数量和,就可以以宽度为索引id,a[i]表示宽度为i的矩形数量,输入一个矩形就是单点增加a[i]+1,查询就是[1,宽度i-1]的数量前缀和,单点修改+区间查询可以用动态数组解决
(2)而三种颜色就是三个树状数组,用来解决
(3)类构造初始化列表:

Tree(ll size):t(size+1,0){}	

等价于:

Tree(ll size){t.resize(size+1,0);}

代码:

#include <bits/stdc++.h>using namespace std;
typedef long long ll;
const int N=1e5+10,mod=1e9+7;
int n;
ll ans;class Tree{private:vector<ll> t;public:Tree(ll size):t(size+1,0){}	// 使用初始化列表//Tree(ll size){t.resize(size+1,0);}// 使用 resize 初始化int lowbit(int x){return x & (-x);} //宽度x的数量++ void update(int x){for(int i=x;i<=N;i+=lowbit(i)){ //宽度最大到N,不是n t[i]++;}}//返回[1,x]的和ll get(int x){ll res=0;for(int i=x;i>0;i-=lowbit(i)){res+=t[i];}return res;} 
};struct Rec{int l,w,c;
}r[N];bool cmp(Rec &r1,Rec &r2){if(r1.l!=r2.l)	return r1.l>r2.l; //降序排列,树状数组即求小于当前宽度的矩形个数即可//相等则按宽度降序排列,保证不会考虑到return r1.w>r2.w; 
}int main(){ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);cin>>n;for(int i=1;i<=n;i++){cin>>r[i].l>>r[i].w>>r[i].c;}sort(r+1,r+n+1,cmp);//初始化三个颜色的树状数组 Tree T_R(N); //宽度为索引 Tree T_Y(N);Tree T_B(N);for(int i=1;i<=n;i++){if(r[i].c==0){ans= (ans+T_Y.get(r[i].w-1)+T_B.get(r[i].w-1))%mod;T_R.update(r[i].w);}else if(r[i].c==1){ans= (ans+T_R.get(r[i].w-1)+T_B.get(r[i].w-1))%mod;T_Y.update(r[i].w);}else{ans= (ans+T_R.get(r[i].w-1)+T_Y.get(r[i].w-1))%mod;T_B.update(r[i].w);}}cout<<ans;return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词