一本通提高篇树状数组做题集

前奏

做树状数组的题之前,需要做三道板子题:

板子题1——单点修改,区间查询

板子题就不写题解了哈╮(╯▽╰)╭

代码
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
int n,q,a[1000005],c[1000005];
void update(int t,int v)
{
    for (int x=t; x<=n; x+=x&-x) c[x]+=v;
}
int getsum(int t)
{
    int ans=0;
    for (int x=t; x; x-=x&-x) ans+=c[x];
    return ans;
}
signed main()
{
    scanf("%lld%lld",&n,&q);
    for (int i=1; i<=n; i++) scanf("%lld",&a[i]),update(i,a[i]);
    for (int i=1; i<=q; i++){
        int x,l,r;
        scanf("%lld%lld%lld",&x,&l,&r);
        if (x==1) update(l,r);
        if (x==2) printf("%lld\n",getsum(r)-getsum(l-1));
    }
    return 0;
}

板子题2——区间修改,单点查询

代码
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
int n,q,a[1000005],c[1000005];
void update(int x,int v)
{
    for (; x<=n; x+=x&-x) c[x]+=v;
}
int getsum(int x)
{
    int sum=0;
    for (; x>0; x-=x&-x) sum+=c[x];
    return sum;
}
signed main()
{
    scanf("%lld",&n);
    scanf("%lld",&q);
    int last=0;
    for (int i=1; i<=n; i++) {scanf("%lld",&a[i]); update(i,a[i]-last); last=a[i];}
    for (int i=1; i<=q; i++){
        int f;
        scanf("%lld",&f);
        if (f==1) {
            int x,y,v;
            scanf("%lld%lld%lld",&x,&y,&v);
            update(x,v); update(y+1,-v);
        }
        else{
            long long ans; int x;
            scanf("%lld",&x);
            ans=getsum(x);
            printf("%lld\n",ans);
        }
    }
}

板子题3——区间修改,区间查询

代码
#include
#include
#define ll long long
using namespace std;
int n,q;
ll a[1000005],c1[1000005],c2[1000005];
void update(int x,int v)
{
    for (int X=x; X<=n;X+=X&-X) c1[X]+=v,c2[X]+=(ll)v*x;
}
ll getsum(int x)
{
    ll sum=0;
    for (int X=x; X>0; X-=X&-X) sum+=(ll)(x+1)*c1[X]-c2[X];
    return sum;
}
int main()
{
    scanf("%d%d",&n,&q);
    for (int i=1; i<=n; i++) scanf("%lld",&a[i]),a[i]+=a[i-1];
    while (q--){
        char st[3];
        scanf("%s",st);
        if (st[0]=='2'){
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%lld\n",getsum(y)-getsum(x-1)+a[y]-a[x-1]); 
        }
        else {
            int x,y,v;
            scanf("%d%d%d",&x,&y,&v);
            update(x,v); update(y+1,-v);
        }
    }
    return 0;
}

正式刷题!!

T1——数星星Ural 1028/loj10114

题解

因为输入时题目已经帮我们排序排好了,而又经过一番推理得:若是排好的数据,则和y轴无关,当前星星的级数就是该星星前面所有x轴小于等于该星星的x轴大小的数量之和。接下来就可以愉快地码代码啦~~~

代码
#include
#include
#include
#include
#include
#include
using namespace std;
int n,a[1000005],c[1000005],ans[1000005];
void update(int x,int v)
{
    for (; x<=40000; x+=x&-x) c[x]+=v;
}
int getsum(int x)
{
    int ans=0;
    for (; x; x-=x&-x) ans+=c[x];
    return ans;
}
int main()
{
    scanf("%d",&n);
    for (int i=1; i<=n; i++){
        int x,y;
        scanf("%d%d",&x,&y);
        x++;
        ans[getsum(x)]++;
        update(x,1);
    }
    for (int i=1; i<=n; i++) printf("%d\n",ans[i-1]);
    return 0;
}

T2——校门外的树vijos 1148 \ loj 10115

题解

将该题转化为括号序列,在一段区间种一种树相当于在 l l 的位置加入一个(,在 r r 的位置加入一个右括号。
维护两个树状数组,一个记录左括号,一个记录右括号,答案就呼之欲出了

代码
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,c[1000005][2],a[1000005];
void update(int x,int y,int t)
{
    for (; x<=n; x+=x&-x) c[x][t]+=y;
}
int getsum(int x,int t)
{
    int ans=0;
    for (; x; x-=x&-x) ans+=c[x][t];
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1; i<=m; i++){
        int x,l,r;
        scanf("%d%d%d",&x,&l,&r);
        if (x==1) update(l,1,0),update(r,1,1);
        if (x==2) printf("%d\n",getsum(r,0)-getsum(l-1,1));
    }
    return 0;
}

T3——清点人数loj 10116

题解

树状数组裸题啊~~,不写了

代码
#include
#include
#include
#include
#include
#include
using namespace std;
int n,k,c[1000005];
char ch[1005];
void update(int x,int y)
{
    for (; x<=n; x+=x&-x) c[x]+=y;
}
int getsum(int x)
{
    int ans=0;
    for (; x; x-=x&-x) ans+=c[x];
    return ans;
}
int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1; i<=k; i++){
        scanf("%s",ch);
        if (ch[0]=='A') {
            int x;
            scanf("%d",&x);
            printf("%d\n",getsum(x));
        }
        if (ch[0]=='B'){
            int x,y;
            scanf("%d%d",&x,&y);
            update(x,y);
        }
        if (ch[0]=='C'){
            int x,y;
            scanf("%d%d",&x,&y);
            update(x,-y);
        }
    }
    return 0;
}

T4——[CQOI 2006]简单题loj 10117

题解

高仿T2,不想多说╮(╯▽╰)╭
为什么越到后面越简单了呢╮(╯▽╰)╭

代码
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,c[1000005][2];
void update(int x,int y,int t)
{
    for (; x<=n; x+=x&-x) c[x][t]+=y;
}
int getsum(int x,int t)
{
    int ans=0;
    for (; x; x-=x&-x) ans+=c[x][t];
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1; i<=m; i++){
        int x; scanf("%d",&x);
        if (x==1) {
            int l,r;
            scanf("%d%d",&l,&r);
            update(l,1,0); update(r,1,1);
        }
        if (x==2){
            int t; scanf("%d",&t);
            printf("%d\n",(getsum(t,0)-getsum(t-1,1))&1);
        }
    }
    return 0;
}

好啦,就写这些辣,多写也没什么意思不是吗╮(╯▽╰)╭

你可能感兴趣的:(一本通提高篇)