树状数组大杀器

点加减,区间和查询:luogu P 3374

#include <algorithm>
#include  <iostream>
#include   <cstring>
#include    <string>
#include    <cstdio>
#include    <vector>
#include    <bitset>
#include     <stack>
#include     <queue>
#include     <cmath>
#include       <set>
#include       <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
const int MAXN=5e5+10;
struct BIT{
    ll c[MAXN];
    int n;
    void init(int _n){
        n=_n;
        rep(i,1,n)c[i]=0;
    }
    void update(int pos,ll val){
        while(pos<=n){
            c[pos]+=val;
            pos+=pos&-pos;
        }
    }
    ll query(int pos){
        ll res=0;
        while(pos){
            res+=c[pos];
            pos-=pos&-pos;
        }
        return res;
    }
}bit;
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    bit.init(n);
    rep(i,1,n){
        ll w;
        scanf("%lld",&w);
        bit.update(i,w);
    }
    while(m--){
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);
        if(op==1){
            bit.update(x,y);
        }else{
            printf("%lld\n",bit.query(y)-bit.query(x-1));
        }
    }
    return 0;
}

思考:如果是点修改,而不是加减怎么办。

  • 用一个辅助数组a[i] 记录当前i位置的值,把这个数修改成x,等同于在i位置加上w,那么有a[i]+w=x 所以w=a[i]-x;

区间加减,点查询:luogu P3368

#include <algorithm>
#include  <iostream>
#include   <cstring>
#include    <string>
#include    <cstdio>
#include    <vector>
#include    <bitset>
#include     <stack>
#include     <queue>
#include     <cmath>
#include       <set>
#include       <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
const int MAXN=5e5+10;
struct BIT{
    ll c[MAXN];
    int n;
    void init(int _n){
        n=_n;
        rep(i,1,n)c[i]=0;
    }
    void update(int pos,ll val){
        while(pos<=n){
            c[pos]+=val;
            pos+=pos&-pos;
        }
    }
    ll query(int pos){
        ll res=0;
        while(pos){
            res+=c[pos];
            pos-=pos&-pos;
        }
        return res;
    }
}bit;
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    bit.init(n);
    rep(i,1,n){
        ll x;
        scanf("%lld",&x);
        bit.update(i,x);
        bit.update(i+1,-x);
    }
    while(m--){
        int op;
        scanf("%d",&op);
        if(op==1){
            int x,y;
            ll k;
            scanf("%d%d%lld",&x,&y,&k);
            bit.update(x,k);
            bit.update(y+1,-k);
        }else{
            int x;
            scanf("%d",&x);
            printf("%lld\n",bit.query(x));
        }
    }
    return 0;
}

  • 光做模板题是不行的一定要熟练运用

CF 961 E Tufurama

题意

  • n个数 代表第i季剧有j集,问存在多少对(x,y)满足存在x季y集和y季x集。

思路

  • 思考找到合适的操作顺序
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pb push_back
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;
/*--------------------------*/
const int MAXN=2e5+10;
int n;
ll a[MAXN];
void update(int i,int v){
    while(i<=n){
        a[i]+=v;
        i+=i&-i;
    }
}
ll query(int i){
    ll res=0;
    while(i){
        res+=a[i];
        i-=i&-i;
    }
    return res;
}
vi v[MAXN];
int x[MAXN];
int main(){
    scanf("%d",&n);
    ll ans=0;
    rep(i,1,n){
        scanf("%d",&x[i]);
        x[i]=min(x[i],n);
        v[min(i-1,x[i])].pb(i);
    }
    rep(i,1,n){
        update(1,1);
        update(x[i]+1,-1);
        for(auto w:v[i]){
            ans+=query(w);
        }
    }
    printf("%I64d",ans);
    return 0;
}

树状数组kth 问题 poj 2828 Buy Tickets

题意

  • 经典插队问题

思路

  • 倒序处理
#include<cstdio>
#include<cstring>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
typedef long long ll;
const int MAXN=2e5+10;
int n;
int a[MAXN],b[MAXN],c[MAXN],ans[MAXN];
void update(int i,int v){
    while(i<=n){
        c[i]+=v;
        i+=i&-i;
    }
}
int findpos(int v){
    int sum=0;
    int pos=0;
    int i=1;
    for(;i<n;i<<=1);
    for(;i;i>>=1){
        if(pos+i<=n&&sum+c[pos+i]<v){
            pos+=i;
            sum+=c[pos];
        }
    }
    return pos+1;
}
int main(){
    while(~scanf("%d",&n)){
        memset(c,0,sizeof(c));
        rep(i,1,n){
            scanf("%d%d",&a[i],&b[i]);
            a[i]++;
            update(i,1);
        }
        per(i,n,1){
            int pos=findpos(a[i]);
            ans[pos]=b[i];
            update(pos,-1);
        }
        rep(i,1,n){
            printf("%d ",ans[i]);
        }
        puts("");
    }
    return 0;
}

POJ 2886 Who Gets the Most Candies?

题意

  • 题意比较繁琐,需要一点点数论知识。
#include<cstdio>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
const int MAXN=5e5+10;
int cnt[MAXN];
int w[MAXN];
char name[MAXN][15];
int a[MAXN];
struct BIT{
    int n;
    ll c[MAXN<<1];
    void init(int _n){
        n=_n;
        rep(i,0,n)c[i]=0;
    }
    void update(int i,ll v){
        for(;i<=n;i+=i&-i)c[i]+=v;
    }
    ll query(int i){
        ll s=0;
        for(;i;i-=i&-i)s+=c[i];
        return s;
    }
    int findpos(ll v){// >=v,if can't find ,return n+1;
        ll sum=0;
        int pos=0;
        int i=1;
        for(;i<n;i<<=1);
        for(;i;i>>=1){
            if(pos+i<=n&&sum+c[pos+i]<v){
                sum+=c[pos+i];
                pos+=i;
            }
        }
        return pos+1;
    }
}bit;
int main(){
    rep(i,1,500000){
        for(int j=i;j<=500000;j+=i){
            cnt[j]++;
        }
    }
    w[1]=1;
    rep(i,2,500000){
        if(cnt[i]>cnt[w[i-1]]){
            w[i]=i;
        }else{
            w[i]=w[i-1];
        }
    }
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        bit.init(n);
        int k=w[n];
        rep(i,1,n){
            scanf("%s%d",name[i],&a[i]);
            bit.update(i,1);
        }
        int now=m;
        int pos=m;
        rep(i,1,k){
            if(i==k){
                printf("%s %d\n",name[pos],cnt[k]);
                break;
            }
            bit.update(pos,-1);
            if(a[pos]>0){
                now=(now-2+a[pos]+(n-1))%(n-1)+1;
                pos=bit.findpos(now);
            }else{
                now=now-(-a[pos])%(n-1);
                while(now<=0)now+=(n-1);
                while(now>(n-1))now-=(n-1);
                pos=bit.findpos(now);
            }
            n--;
        }
    }
    return 0;
}

树状数组动态开点 CF 669E Little Artem and Time Machine

题意

  • 三个操作,1在x时刻添加一个y,2在x时刻减少一个y,3在x时刻查询有几个y

思路

  • 因为总操作数只有1e5,离散化动态开树状数组就好了
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
map<int,int> M[MAXN];
map<int,int> vis;
int tot=1;
int n=1e9+10;
void update(int tp,int i,int v){
    while(i<=n){
        M[tp][i]+=v;
        i+=i&-i;
    }
}
int query(int tp,int i){
    int res=0;
    while(i){
        res+=M[tp][i];
        i-=i&-i;
    }
    return res;
}
int main(){
    int q;
    scanf("%d",&q);
    while(q--){
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);
        if(op==1&&vis[y]==0){
            vis[y]=tot++;
        }
        if(op==1)update(vis[y],x,1);
        if(op==2)update(vis[y],x,-1);
        if(op==3)printf("%d\n",query(vis[y],x));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值