树状数组

单点修改,区间查询

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x&(-x))
const int N=5e5+10;
int a[N],s[N];
int n,m;
void add(int x,int k){
    for(int i=x;i<=n;i+=lowbit(i)){
        s[i]+=k;
    }
}
int searchs(int l,int r){
    int ans=0;
    for(int i=r;i;i-=lowbit(i)){
        ans+=s[i];
    }
    for(int i=l-1;i;i-=lowbit(i)){
        ans-=s[i];
    }
    return ans;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        add(i,a[i]);
    }
    while(m--){
        int op;
        cin>>op;
        if(op==1){
            int x,k;
            cin>>x>>k;
            add(x,k);
        }
        else{
            int l,r;
            cin>>l>>r;
            cout<<searchs(l,r)<<endl;
        }
    }
}

区间修改,单点查询

存储差分数组,在区间+k就是把l位置+k,r+1位置-k,然后单点查询就是查询1到x的和

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x&(-x))
const int N=5e5+10;
int a[N],s[N];
int n,m;
void add(int x,int k){
    for(int i=x;i<=n;i+=lowbit(i)){
        s[i]+=k;
    }
}
int searchs(int l,int r){
    int ans=0;
    for(int i=r;i;i-=lowbit(i)){
        ans+=s[i];
    }
    for(int i=l-1;i;i-=lowbit(i)){
        ans-=s[i];
    }
    return ans;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        add(i,a[i]-a[i-1]);
    }
    while(m--){
        int op;
        cin>>op;
        if(op==1){
            int x,y,k;
            cin>>x>>y>>k;
            add(x,k);
            add(y+1,-k);
        }
        else{
            int x;
            cin>>x;
            cout<<searchs(1,x)<<endl;
        }
    }
}

逆序对个数 

数可能会很大,把他离散化,保留原有顺序,从左往右遍历,这样统计的是左边出现的比他大的数(即逆序对)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x&(-x))
const int N=5e5+10;
int r[N],tr[N];
int n,m,ans;
struct T{
    int v,id;
}a[N];
bool cmp(T a1,T a2){
    if(a1.v==a2.v)return a1.id<a2.id;
    return a1.v<a2.v;
}
void add(int x,int k){
    for(int i=x;i<=n;i+=lowbit(i)){
        tr[i]+=k;
    }
}
int searchs(int l,int r){
    int ans=0;
    for(int i=r;i;i-=lowbit(i)){
        ans+=tr[i];
    }
    for(int i=l-1;i;i-=lowbit(i)){
        ans-=tr[i];
    }
    return ans;
}
signed main(){
   cin>>n;
   for(int i=1;i<=n;i++){
    cin>>a[i].v;
    a[i].id=i;
   }
   sort(a+1,a+n+1,cmp);
   for(int i=1;i<=n;i++){
    r[a[i].id]=i;
   }
   for(int i=1;i<=n;i++){
       int y=r[i];
       ans+=searchs(1,n)-searchs(1,y);
       add(y,1);
   }
   cout<<ans<<endl;
}

 

练习

楼兰图腾

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x&(-x))
const int N=5e5+10;
int a[N],s[N];
int llow[N],lgre[N];
int rlow[N],rgre[N];
int n,m;
void add(int x,int k){
    for(int i=x;i<=n;i+=lowbit(i)){
        s[i]+=k;
    }
}
int searchs(int l,int r){
    int ans=0;
    for(int i=r;i;i-=lowbit(i)){
        ans+=s[i];
    }
    for(int i=l-1;i;i-=lowbit(i)){
        ans-=s[i];
    }
    return ans;
}
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    //从小打到遍历,统计的是每个数左边比它小的个数,和比他大的个数
    for(int i=1;i<=n;i++){
        int y=a[i];
        llow[i]=searchs(1,y-1);
        lgre[i]=searchs(1,n)-searchs(1,y);
        add(y,1);
    }
    memset(s,0,sizeof(s));
    //从右往左遍历,统计的是这个数右边比他大的和比他小的个数
    int ans1=0,ans2=0;
    for(int i=n;i>=1;i--){
        int y=a[i];
        ans2+=llow[i]*searchs(1,y-1);
        ans1+=lgre[i]*(searchs(1,n)-searchs(1,y));
        add(y,1);
    }
    cout<<ans1<<' '<<ans2<<endl;
}

区间修改,区间查询

对于区间修改我们照样用差分存储改为单点修改,区间查询的话我们公式推导后可以发现需要另一个树状数组来存储i*d的差分来求前缀和

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x&(-x))
const int N=5e5+10;
int a[N],tr[N],tr2[N];
int n,m;
void add(int tr[],int x,int k){
    for(int i=x;i<=n;i+=lowbit(i)){
        tr[i]+=k;
    }
}
int searchs(int tr[],int l,int r){
    int ans=0;
    for(int i=r;i;i-=lowbit(i)){
        ans+=tr[i];
    }
    for(int i=l-1;i;i-=lowbit(i)){
        ans-=tr[i];
    }
    return ans;
}
int sum(int x){
    return searchs(tr,1,x)*(x+1)-searchs(tr2,1,x);
}
signed main(){
   cin>>n>>m;
   for(int i=1;i<=n;i++){
        cin>>a[i];
        int d=a[i]-a[i-1];
        add(tr,i,d);
        add(tr2,i,d*i);
   }
   while(m--){
     char op;
     cin>>op;
     if(op=='Q'){
        int l,r;
        cin>>l>>r;
        cout<<sum(r)-sum(l-1)<<endl;
     }
     else{
        int l,r,d;
        cin>>l>>r>>d;
        add(tr,l,d);add(tr,r+1,-d);
        add(tr2,l,l*d);add(tr2,r+1,(r+1)*(-d));
     }
   }
}

谜一样的牛

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x&(-x))
const int N=5e5+10;
int a[N],tr[N];
int n,m,ans[N];
void add(int x,int k){
    for(int i=x;i<=n;i+=lowbit(i)){
        tr[i]+=k;
    }
}
int searchs(int l,int r){
    int ans=0;
    for(int i=r;i;i-=lowbit(i)){
        ans+=tr[i];
    }
    for(int i=l-1;i;i-=lowbit(i)){
        ans-=tr[i];
    }
    return ans;
}
signed main(){
   cin>>n;
   for(int i=2;i<=n;i++)cin>>a[i];
   for(int i=1;i<=n;i++)add(i,1);
   for(int i=n;i>=1;i--){
    int l=1,r=n;
    while(l<r){
        int mid=l+r>>1;
        if(searchs(1,mid)>=a[i]+1){
            r=mid;
        }
        else l=mid+1;
    }
    ans[i]=l;
    add(l,-1);
   }
   for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
}

 

 
posted @ 2022-11-03 19:40  Dengpc  阅读(44)  评论(0)    收藏  举报