树状数组

//树状数组
//利用lowbit函数将区间划分为以二进制结尾的长度的小区间,然后利用这些小区间相加,减少时间复杂度

//树状数组的本质就是前缀和+可修改区间,求单点前缀和,如果是求某一的区间和,需要稍加修改,下面有类似例题,维护前缀和还有i*前缀和就可以
//也就是说树状数组就是更快一点的前缀和,但是比前缀和的功能要多,可维护的种类更广泛

//楼兰图腾
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,mod=1e9+7;
string s;
int n,t,a[N],f[N],res,num,ans,m,g[N],low[N],tr[N];
bool vis[N];
int lowbit(int x){
    return x&-x;
}
void add(int x,int c)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}
int sum(int x)
{
    int op=0;
    for(int i=x;i>=1;i-=lowbit(i)) op+=tr[i];
    return op;
}
signed main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        int y=a[i];
        g[i]=sum(n)-sum(y);
        low[i]=sum(y-1);
        add(y,1);        
    }
    memset(tr,0,sizeof tr);
    for(int i=n;i>=1;i--){
        int y=a[i];
        ans+=g[i]*(sum(n)-sum(y));
        num+=low[i]*(sum(y-1));
        add(y,1);
    }
    cout<<ans<<" "<<num<<endl;
    return 0;
}

//一个简单的整数问题
//区间加数,求单点值
//利用树状数组与差分
//用树状数组维护差分
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,mod=1e9+7;
string s;
int n,t,a[N],f[N],res,num,ans,m,tr[N];
bool vis[N];
int lowbit(int x){
    return x&-x;
}
void add(int x,int c)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}
int sum(int x)
{
    int op=0;
    for(int i=x;i>=1;i-=lowbit(i)) op+=tr[i];
    return op;
}
signed main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) add(i,a[i]-a[i-1]);
    while(m--){
        char s;
        int x,y,z;
        cin>>s;
        if(s=='C'){
            cin>>x>>y>>z;
            add(x,z),add(y+1,-z);
        }
        else if(s=='Q'){
            cin>>x;
            cout<<sum(x)<<endl;
        }
    }
    return 0;
}

//一个简单的整数问题2
//区间加+区间和
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,mod=1e9+7;
string s;
int n,t,a[N],f[N],res,num,ans,m,tr1[N],tr2[N];
bool vis[N];
int lowbit(int x){
    return x&-x;
}
void add(int tr[],int x,int c)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}
int sum(int tr[],int x)
{
    int op=0;
    for(int i=x;i>=1;i-=lowbit(i)) op+=tr[i];
    return op;
}
int pre_sum(int x){
    return sum(tr1,x)*(x+1)-sum(tr2,x);
}
signed main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        int y=a[i]-a[i-1];
        add(tr1,i,y),add(tr2,i,i*y);
    }
    while(m--){
        char op;
        int l,r,d;
        cin>>op>>l>>r;
        if(op=='Q') cout<<pre_sum(r)-pre_sum(l-1)<<endl;
        else{
            cin>>d;
            add(tr1,l,d),add(tr1,r+1,-d);
            add(tr2,l,d*l),add(tr2,r+1,-d*(r+1));
        } 
    }
    return 0;
}

//谜一样的牛
//从后向前找,假设现在的值是2,也就是从前到现在这个区间里面,这个牛的位置是第3小的牛
//如果有5头,x=2,也就是说有两头牛比他低,它就是第三小,也就是5-3=2,第2
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,mod=1e9+7;
string s;
int n,t,a[N],f[N],res,num,ans,m,tr[N];
bool vis[N];
int lowbit(int x){
    return x&-x;
}
void add(int x,int c){
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}
int sum(int x){
    int op=0;
    for(int i=x;i>=1;i-=lowbit(i)) op+=tr[i];
    return op;
}
signed main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) add(i,1);
    for(int i=n;i>=1;i--){
        int y=a[i]+1;
        int l=0,r=n;
        while(l<r){
            int mid=l+r>>1;
            if(sum(mid)>=y) r=mid;
            else l=mid+1;
        }
        f[i]=r;
        add(r,-1);
    }
    for(int i=1;i<=n;i++) cout<<f[i]<<" ";
    return 0;
}

 【精选】树状数组(详细分析+应用),看不懂打死我!-CSDN博客

posted @ 2023-07-20 14:54  o-Sakurajimamai-o  阅读(15)  评论(0)    收藏  举报
-- --