树状数组的认识与模板

我对树状数组的认识可以参考视频1视频2,每个人的理解不一样,建议去观看大牛的理解,视频1讲的不太深入,但还是推荐先去看视频1,再去看视频2.

单点修改,区间最大

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=300005;
int h[maxn],a[maxn];
int n,m;
int lowbit(int x)
{
    return x&(-x);
}
void update(int x)
{
    while(x<=n)
    {
        h[x]=a[x];
        for(int i=1;i<lowbit(x);i<<=1)
        h[x]=max(h[x],h[x-i]);
        x+=lowbit(x);
    }
    return ;
}
void findans(int begin,int end)
{
    int ans=0;
    while(end>=begin)
    {
        ans=max(ans,a[end]);
        end--;
        for(;end-lowbit(end)>=begin;end-=lowbit(end))
        ans=max(ans,h[end]);
    }
    
    printf("%d\n",ans);
    return ;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(h,0,sizeof(h));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            update(i);
        }
        for(int i=1;i<=m;i++)
        {
            char c=getchar();
            while(c!='Q'&&c!='U')c=getchar();
            if(c=='U')//update
            {
                int y,z;
                scanf("%d%d",&y,&z);
                a[y]=z;
                update(y);
                continue;    
            }
            if(c=='Q')//findans
            {
                int y,z;
                scanf("%d%d",&y,&z);
                findans(y,z);
                continue;
            }
        }
    }
    
    return 0;
}
View Code

hdu1166(单点修改区间求和)

#include<bits/stdc++.h>
#define maxn 111111
using namespace std;
int n;
int c[maxn];
int b[maxn];
int lowbit(int x) {
    return x&-x;
}
/**单点修改区间求和**/
/**
add(x,num);
sum(r)-sum(l-1);
每次x号位置修改num
求lr闭区间的和
**/

void add(int k,int num) {
    while(k<=n) {
        c[k]+=num;
        k+=lowbit(k);
    }
}
int sum(int k) {
    int ans=0;
    while(k) {
        ans+=c[k];
        k-=lowbit(k);
    }
    return ans;
}
int main()
{
    int t;
    int kase=0;
    scanf("%d",&t);
    while(t--) {
        memset(c,0,sizeof c);
        printf("Case %d:\n",++kase);
        scanf("%d",&n);
        int x,y;
        for(int i=1;i<=n;i++) {
            scanf("%d",&x);
            add(i,x);
        }
        char s[10];
        while(scanf("%s",s)&&strcmp(s,"End")!=0) {
            if(strcmp(s,"Query")==0) {
                scanf("%d%d",&x,&y);
                printf("%d\n",sum(y)-sum(x-1));
            }
            else {
                if(strcmp(s,"Add")==0) {
                    scanf("%d%d",&x,&y);
                    add(x,y);
                }
                else {
                    scanf("%d%d",&x,&y);
                    add(x,-y);
                }
            }
        }
    }
    return 0;
}
View Code

hdu 1556(区间修改单点求值)

#include<bits/stdc++.h>
#define maxn 111111
using namespace std;
int n;
int c[maxn];
int b[maxn];
int lowbit(int x) {
    return x&-x;
}
/**区间修改单点询问**/
/**
add(l-1,-num);add(r,num);
sum(x);
每次修改闭区间lr的值,询问x节点的值
**/

void add(int k,int num) {
    while(k) {
        b[k]+=num;
        k-=lowbit(k);
    }
}
int sum(int k) {
    int ans=0;
    while(k<=n) {
        ans+=b[k];
        k+=lowbit(k);
    }
    return ans;
}
int main()
{
     while(scanf("%d",&n)&&(n!=0)) {
        memset(b,0,sizeof b);
        int x,y;
        for(int i=1;i<=n;i++) {
            scanf("%d%d",&x,&y);
            add(x-1,-1);
            add(y,1);
        }
        for(int i=1;i<n;i++) {
            printf("%d ",sum(i));
        }
        printf("%d\n",sum(n));
     }





    return 0;
}
View Code
给出一个全0的矩阵,然后一些操作
0 S:初始化矩阵,维数是S*S,值全为0,这个操作只有最开始出现一次
1 X Y A:对于矩阵的X,Y坐标增加A
2 L B R T:询问(L,B)到(R,T)区间内值的总和
3:结束对这个矩阵的操作
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define MEM(a,x) memset(a,x,sizeof(a))
#define LL long long
#define N 2005
#define INF 0x3f3f3f3f
#define lowbit(x) (x&-x)
const int mod = 1e9+7;

int a[N];
int n,c[N][N],ans[N],x,y;

int sum(int x,int y)
{
    int ret=0,i,j;
    for(i = x; i>0; i-=lowbit(i))
    {
        for(j = y; j>0; j-=lowbit(j))
        {
            ret+=c[i][j];
        }
    }
    return ret;
}

void add(int x,int y,int d)
{
    int i,j;
    for(i = x; i<=n; i+=lowbit(i))
    {
        for(j = y; j<=n; j+=lowbit(j))
        {
            c[i][j]+=d;
        }
    }
}

int main()
{
    int i,j,k,op,x,y;
    while(~scanf("%d%d",&i,&n))
    {
        MEM(c,0);
        while(1)
        {
            scanf("%d",&op);
            if(op==3)
                break;
            if(op==1)
            {
                scanf("%d%d%d",&x,&y,&k);
                add(x+1,y+1,k);
            }
            else
            {
                int l,b,r,t;
                scanf("%d%d%d%d",&l,&b,&r,&t);
                l++,b++,r++,t++;
                printf("%d\n",sum(r,t)-sum(r,b-1)-sum(l-1,t)+sum(l-1,b-1));
            }
        }
    }

    return 0;
}
View Code

 

区间修改,区间和

理解

题目描述 Description

给你N个数,有两种操作:


1:给区间[a,b]的所有数增加X


2:询问区间[a,b]的数的和。

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,

 

再接下来一个正整数Q,每行表示操作的个数,

 

如果第一个数是1,后接3个正整数,

 

表示在区间[a,b]内每个数增加X,如果是2,

 

表示操作2询问区间[a,b]的和是多少。

 

pascal选手请不要使用readln读入

输出描述 Output Description

对于每个询问输出一行一个答案

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<set>
const int MAXN=200000*4;
using namespace std;
int lowbit(int x){return x&(-x);}
int n,Q,opt,x,y;
long long A[MAXN],C[MAXN],sum[MAXN],z;
void modifyA(int x,int val){
    while(x<=n){
        A[x]+=val;
        x+=lowbit(x);
    }
}
void modifyC(int x,long long val){
    while(x<=n){
        C[x]+=val;
        x+=lowbit(x);
    }
}
void update(int from,int to,long long val){
    modifyA(from,val);
    modifyA(to+1,-val);
    modifyC(from,val*from);
    modifyC(to+1,-val*(to+1));
}
long long queryA(int loc){
    long long ans=0;
    while(loc){
        ans+=A[loc];
        loc-=lowbit(loc);
    }
    return ans;
}
long long queryC(int loc){
    long long ans=0;
    while(loc){
        ans+=C[loc];
        loc-=lowbit(loc);
    }
    return ans;
}
long long query(int loc){
    return sum[loc]+(loc+1)*queryA(loc)-queryC(loc);
}
long long query(int from,int to){
    return query(to)-query(from-1);
}
int main(){
    scanf("%d",&n);
    for(register int i=1;i<=n;i++)scanf("%d",&sum[i]),sum[i]+=sum[i-1];
    scanf("%d",&Q);
    while(Q--){
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==1){
            scanf("%lld",&z);
            update(x,y,z);
        }else{
            printf("%lld\n",query(x,y));
        }
    }
    return 0;
}
View Code

 

posted @ 2018-05-30 16:32  shuai_hui  阅读(150)  评论(0编辑  收藏  举报