马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
先容
树状数组的推导
两个底子操纵
模板-acwing795. 前缀和
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 1e6+10;
- int c[N];
- int lowbit(int x){
- return x & -x;
- }
- int query(int x){
- int ans = 0;
- for(; x; x -= lowbit(x)) ans += c[x];
- return ans;
- }
- void add(int x,int y){
- for(; x <= N; x += lowbit(x)) c[x] += y;
- }
- int main(){
- int n,m; scanf("%d%d",&n,&m);
- for(int i = 1; i <= n; i++){
- int num; scanf("%d",&num);
- add(i,num);
- }
- while(m--){
- int l,r; scanf("%d%d",&l,&r);
- printf("%d\n",query(r)-query(l-1));
- }
- return 0;
- }
复制代码 模板-acwing5910. 求逆序对
-
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long LL;
- const int N = 1e6+10;
- LL c[N],a[N];
- int lowbit(int x) // 返回末尾的1
- {
- return x & -x;
- }
- LL query(int x){
- LL ans = 0;
- for(; x; x -= lowbit(x)) ans += c[x];
- return ans;
- }
- void add(int x,int y){
- for(; x <= N; x += lowbit(x)) c[x] += y;
- }
- int main()
- {
- LL ans = 0;
- int n; scanf("%d",&n);
- for(int i = 1; i <= n; i++){
- scanf("%d",&a[i]);
- }
- //倒序扫描,找值比当前这个数小但是先进入树状数组的数,即1-(a[i]-1)的和,加入ans(根据逆序对的定义构造的)
- for(int i = n; i >= 1; i--){
- ans += query(a[i]-1)-query(0);
- add(a[i],1);
- }
- printf("%lld\n",ans);
- return 0;
- }
-
复制代码 P3374 【模板】树状数组 1
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 1e6+10;
- long long c[N];
- int lowbit(int x){
- return x & -x;
- }
- long long query(int x){
- long long ans = 0;
- for(; x; x -= lowbit(x)) ans += c[x];
- return ans;
- }
- void add(int x,int y){
- for(; x <= N; x += lowbit(x)) c[x] += y;
- }
- int main(){
- long long n,m; scanf("%lld%lld",&n,&m);
- for(int i = 1; i <= n; i++){
- long long x; scanf("%lld",&x);
- add(i,x);
- }
- while(m--){
- long long t,idx,x,l,r; scanf("%lld",&t);
- if(t == 1){
- scanf("%lld%lld",&idx,&x);
- add(idx,x);
- }else{
- scanf("%lld%lld",&l,&r);
- printf("%lld\n",query(r)-query(l-1));
- }
- }
- return 0;
- }
复制代码 P3368
- #include <bits/stdc++.h>
- using namespace std;
- const int N = 1e6 + 10;
- int n, m, c[N],a[N];
- int lowbit(int x){
- return x & -x;
- }
- void add(int x, int y){
- for (int i = x; i <= n; i += lowbit(i)) c[i] += y;
- }
- int fn(int x){
- int cnt = 0;
- for (int i = x; i; i -= lowbit(i)) cnt += c[i];
- return cnt;
- }
- int main()
- {
- cin >> n >> m;
- for (int i = 1; i <= n; i++){
- cin >> a[i];
- add(i, a[i] - a[i - 1]);
- }
-
- while (m--){
- int t; cin >> t;
- if (t == 1){
- int x, y, k; cin >> x >> y >> k;
- add(x, k); add(y + 1, -k);
- }
- else {
- int x; cin >> x;
- cout << fn(x) << endl;
- }
- }
- return 0;
- }
复制代码 例题
A. 数列操纵
思绪
模板题,套树桩数组的模板即可。留意开long long
代码
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 1e6+10;
- long long c[N];
- int lowbit(int x){
- return x & -x;
- }
- long long query(int x){
- long long ans = 0;
- for(; x; x -= lowbit(x)) ans += c[x];
- return ans;
- }
- void add(int x,int y){
- for(; x <= N; x += lowbit(x)) c[x] += y;
- }
- int main(){
- long long n,m; scanf("%lld%lld",&n,&m);
- for(int i = 1; i <= n; i++){
- long long x; scanf("%lld",&x);
- add(i,x);
- }
- while(m--){
- long long t,idx,x,l,r; scanf("%lld",&t);
- if(t == 1){
- scanf("%lld%lld",&idx,&x);
- add(idx,x);
- }else{
- scanf("%lld%lld",&l,&r);
- printf("%lld\n",query(r)-query(l-1));
- }
- }
- return 0;
- }
复制代码 B. 数星星 Stars
思绪
这道题的求解思绪跟逆序对那道题差不多,都是利用树状数组去查1-x的和,但是这道题要思量好一种雷同交心的思绪,就是他要找左下角的星星个数,他输入时是按照y增序,y雷同时按照x增序给出,那么某个星星的品级就是x坐标1-x的星星个数,但是要留意的是这道题有大概会坐标会为0那么就会出现越界题目,以是每次要给x坐标+1,但是团体每个数的巨细关系并不会改变。
代码
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 1e6+10;
- long long c[N],lv[N];
- int lowbit(int x){
- return x & -x;
- }
- long long query(int x){
- long long ans = 0;
- for(; x; x -= lowbit(x)) ans += c[x];
- return ans;
- }
- void add(int x,int y){
- for(; x <= N; x += lowbit(x)) c[x] += y;
- }
- int main(){
- int n; cin >> n;
- for(int i = 1; i <= n; i++){
- int x,y; cin >> x >> y;
- x++;
- int t = query(x);
- lv[t]++;
- add(x,1);
- }
- for(int i = 0; i < n; i++) cout << lv[i] << endl;
- return 0;
- }
复制代码 C. 校门外的树
思绪
这道题由于是求某个区间内树的数目,树在区间内的具体位置是不知道的,以是用两个数组分别表现该点左侧树的数目和该点右侧树的数目,区间[a,b]内树的数目=b点左侧树的数目 – (a-1)点右侧树的数目。之以是是a-1点不是a点是由于要算上a点上的树。
代码
- #include <bits/stdc++.h>
- using namespace std;
- int const N = 50010;
- int n, m;
- // 树状数组模板
- int c1[N], c2[N];
- #define lowbit(x) (x & -x)
- typedef long long LL;
- void add(int c[], int x, int v) {
- while (x < N) c[x] += v, x += lowbit(x);
- }
- LL sum(int c[], int x) {
- LL res = 0;
- while (x) res += c[x], x -= lowbit(x);
- return res;
- }
- //这道题因为是求某个区间内树的数量,树在区间内的具体位置是不知道的
- //所以用两个数组分别表示该点左侧树的数量和该点右侧树的数量
- //区间[a,b]内树的数量=b点左侧树的数量 – (a-1)点右侧树的数量。之所以是a-1点不是a点是因为要算上a点上的树。
- int main() {
- int k, l, r;
- scanf("%d%d", &n, &m);
- for (int i = 1; i <= m; i++) {
- scanf("%d%d%d", &k, &l, &r);
- if (k == 1)
- add(c1, l, 1), add(c2, r, 1); // c1记录左括号的个数,c2记录右括号的个数
- else
- printf("%d\n", sum(c1, r) - sum(c2, l - 1));
- }
- return 0;
- }
复制代码 D. 盘货人数
思绪
模板题,直接套模板。开long long
代码
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 1e6+10;
- long long c[N],lv[N];
- int lowbit(int x){
- return x & -x;
- }
- long long query(int x){
- long long ans = 0;
- for(; x; x -= lowbit(x)) ans += c[x];
- return ans;
- }
- void add(int x,int y){
- for(; x <= N; x += lowbit(x)) c[x] += y;
- }
- int main(){
- int n,k; cin >> n >> k;
- for(int i = 1; i <= k; i++){
- char t;
- int m,p;
- cin >> t;
- if(t == 'A'){
- scanf("%d",&m);
- printf("%d\n",query(m));
- }else if(t == 'B'){
- scanf("%d%d",&m,&p);
- add(m,p);
- }else {
- scanf("%d%d",&m,&p);
- add(m,-p);
- }
- }
- return 0;
- }
复制代码 E. 简单题
思绪
这道题大概是这几道题中较难的一道,这道题如果不是取反操纵的话,就是一道树状数组区间修改区间查询的题了,但是他是取反操纵,我们就可以简化一下,不消像区间修改一样另开一个前缀和数组,接下来解说本体思绪:
根据差分头脑,可以在从1~l先取反一次,再在1~r+1取反一次就可以得到l-r取反了,取反操纵就异或上1即可(^1),求某一位的值即从1~x的异或值就第x位的值。
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 1e6+10;
- bool c[N];
- int n,m;
- int lowbit(int x){
- return x & -x;
- }
- bool query(int x){
- bool ans = 0;
- for(; x; x -= lowbit(x)) ans ^= c[x];
- return ans;
- }
- void add(int x){
- for(; x <= N; x += lowbit(x)) c[x] ^= 1;
- }
- void modify(int l, int r) // 原数组的区间修改 <- 差分数组的单点修改
- {
- add(l);
- if (r != n)
- add(r+1);
- }
- int main(){
- cin >> n >> m;
- for(int i = 1; i <= m; i++){
- char t;
- int x,l,r;
- cin >> t;
- if(t == '2'){
- scanf("%d",&x);
- printf("%d\n",query(x));
- }else{
- scanf("%d%d",&l,&r);
- modify(l,r);
- }
- }
- return 0;
- }
复制代码
|