树状数组专题

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组专题相关的知识,希望对你有一定的参考价值。

接下里复习专题:数据结构、图论、数学(大致过一遍经典题型)
出了跟队友vp,剩下时间自己找icpc进行vp,两天一场加上补题
我不会在这里倒下的,得不到想要的绝不轻易松手

P3608 [USACO17JAN]Balanced Photo G

板子题:两次建树,分别同统计出左端小于等于a[i]-1的数目,再用总的数目i减去自身和小于a[i]的数目;同理右端也一样。

#include <bits/stdc++.h>
#define endl '\\n'
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define PII pair<int,int>

using namespace std;
const int N =2e6+5;
const int inf=1e18;
const int mod=998244353;
int n,a[N],b[N],tr[N],pl[N],pr[N];
int lowbit(int x)

    return x&(-x);

void add(int u,int val)

    for(;u<=n;u+=lowbit(u)) tr[u]+=val;

int ask(int u)

    int res=0;
    for(;u;u-=lowbit(u))
    
        res+=tr[u];
    
    return res;


void solve()

    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],b[i]=a[i];
    sort(b+1,b+n+1);
    int len=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(b+1,b+n+1,a[i])-b;
//    for(int i=1;i<=n;i++)
//        cout<<a[i]<<" ";
//    cout<<endl;
    for(int i=1;i<=n;i++)
    
        pl[i]=i-1-ask(a[i]-1);
        add(a[i],1);
    
    memset(tr,0,sizeof tr);
    for(int i=n;i>=1;i--)
    
        pr[i]=n-i+1-1-ask(a[i]-1);
        add(a[i],1);
    
//    for(int i=1;i<=n;i++) cout<<pr[i]<<" ";
//    cout<<endl;
    int ans=0;
    for(int i=1;i<=n;i++)
        if(max(pl[i],pr[i])>2*min(pl[i],pr[i])) ans++;
    cout<<ans<<endl;

signed main()

    //ios;
    //int T;cin>>T;
    //while(T--)
    solve();
    return 0;

P3801 红色的幻想乡

单点修改+区间查询+简单容斥

#include <bits/stdc++.h>
#define endl '\\n'
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define PII pair<int,int>

using namespace std;
const int N =2e6+5;
const int inf=1e18;
const int mod=998244353;
int n,m,q,a[N],b[N],tr[N],tr2[N],mx[N],my[N];
int lowbit(int x)

    return x&(-x);

void add(int tr[],int u,int val)

    for(;u<N;u+=lowbit(u)) tr[u]+=val;

int ask(int tr[],int u)

    int res=0;
    for(;u;u-=lowbit(u)) res+=tr[u];
    return res;


void solve()

    cin>>n>>m>>q;
    while(q--)
    
        int op;cin>>op;
        if(op==1)
        
            int x,y;cin>>x>>y;
            if(mx[x]==0) mx[x]=1,add(tr,x,1);
            else mx[x]=0,add(tr,x,-1);
            if(my[y]==0) my[y]=1,add(tr2,y,1);
            else my[y]=0,add(tr2,y,-1);
        
        else
        
            int sx,sy,dx,dy;cin>>sx>>sy>>dx>>dy;
            int p=ask(tr,dx)-ask(tr,sx-1);
            int q=ask(tr2,dy)-ask(tr2,sy-1);
            int ans=p*(dy-sy+1)+q*(dx-sx+1)-2*p*q;
            cout<<ans<<endl;
        
    

signed main()

    //ios;
    //int T;cin>>T;
    //while(T--)
    solve();
    return 0;

P4231 三步必杀

数学推导+二级差分

#include <bits/stdc++.h>
#define endl '\\n'
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define PII pair<int,int>

using namespace std;
const int N =2e7+5;
const int inf=1e18;
const int mod=998244353;
int n,m,q,a[N],b[N],c[N],tr[N],tr2[N];
int lowbit(int x)

    return x&(-x);

void add(int tr[],int u,int val)

    for(;u<N;u+=lowbit(u)) tr[u]+=val;

int ask(int tr[],int u)

    int res=0;
    for(;u;u-=lowbit(u)) res+=tr[u];
    return res;


void solve()

    cin>>n>>m;
    for(int i=1;i<=m;i++)
    
        int l,r,s,e;cin>>l>>r>>s>>e;
        int d=(e-s)/(r-l);
        a[l]=a[l]+s;
        a[l+1]=a[l+1]+d-s;
        a[r+1]=a[r+1]-e-d;
        a[r+2]=a[r+2]+e;
    
    int mx=0,ans=0;
    for(int i=1;i<=n;i++)
    
        b[i]=b[i-1]+a[i];
        c[i]=c[i-1]+b[i];
        if(c[i]>mx) mx=c[i];
        ans^=c[i];
    
    cout<<ans<<" "<<mx<<endl;

signed main()

    ios;
    //int T;cin>>T;
    //while(T--)
    solve();
    return 0;

P4392 [BOI2007]Sound 静音问题

ST表做法在空间上卡了我一个点MLE了 ,还是得用树状数组写。还是卡过去了,忘记关long long了,好蠢。

#include <bits/stdc++.h>
#define endl '\\n'
//#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define PII pair<int,int>

using namespace std;
const int N =1e6+5;
const int inf=1e18;
const int mod=998244353;
int n,m,c;
bool flag;
int st[1000005][12],st2[1000005][12];

inline int sch(int l,int r)

    int p=log2(r-l+1);
    return max(st[l][p],st[r-(1<<p)+1][p]);

inline int sch2(int l,int r)

    int p=log2(r-l+1);
    return min(st2[l][p],st2[r-(1<<p)+1][p]);


void solve()

    cin>>n>>m>>c;
    for(int i=1; i<=n; i++)
    
        int x;
        cin>>x;
        st[i][0]=st2[i][0]=x;
    
    for(int j=1; (1<<j)<=m; j++)
        for(int i=1; i-1+(1<<j)<=n; i++)
        
            st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
            st2[i][j]=min(st2[i][j-1],st2[i+(1<<j-1)][j-1]);
        
    for(int i=1; i<=n-m+1; i++)
    
        int r=sch(i,i+m-1),l=sch2(i,i+m-1);
        if(r-l<=c)
        
            flag=1;
            cout<<i<<endl;
        
    
    if(flag==0) cout<<"NONE"<<endl;

signed main()

    //ios;
    //int T;cin>>T;
    //while(T--)
    solve();
    return 0;




以上是关于树状数组专题的主要内容,如果未能解决你的问题,请参考以下文章

codevs 4163 求逆序对的数目 -树状数组法

求逆序数数目(树状数组+离散化)

Mobile phones(二维树状数组) POJ - 1195

火柴排队(NOIP2013)(附树状数组专题讲解(其实只是粗略。。。))

算法系列学习线段树vs树状数组 单点修改,区间查询 [kuangbin带你飞]专题七 线段树 A - 敌兵布阵

Bubble Sort HDU - 5775 树状数组