我想要打一个主席树

Posted

tags:

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

这里提供了静态主席树及动态主席树(树状数组套主席树)的模板。
分别应用于静态区间第k小及动态区间第k小。
静态:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#pragma GCC optimize(2) 
#pragma GCC optimize(3) 
#pragma GCC target("avx") 
#pragma GCC optimize("Ofast") 
#pragma GCC optimize("inline") 
#pragma GCC optimize("-fgcse") 
#pragma GCC optimize("-fgcse-lm") 
#pragma GCC optimize("-fipa-sra") 
#pragma GCC optimize("-ftree-pre") 
#pragma GCC optimize("-ftree-vrp") 
#pragma GCC optimize("-fpeephole2") 
#pragma GCC optimize("-ffast-math") 
#pragma GCC optimize("-fsched-spec") 
#pragma GCC optimize("unroll-loops") 
#pragma GCC optimize("-falign-jumps") 
#pragma GCC optimize("-falign-loops") 
#pragma GCC optimize("-falign-labels") 
#pragma GCC optimize("-fdevirtualize") 
#pragma GCC optimize("-fcaller-saves") 
#pragma GCC optimize("-fcrossjumping") 
#pragma GCC optimize("-fthread-jumps") 
#pragma GCC optimize("-funroll-loops") 
#pragma GCC optimize("-fwhole-program") 
#pragma GCC optimize("-freorder-blocks") 
#pragma GCC optimize("-fschedule-insns") 
#pragma GCC optimize("inline-functions") 
#pragma GCC optimize("-ftree-tail-merge") 
#pragma GCC optimize("-fschedule-insns2") 
#pragma GCC optimize("-fstrict-aliasing") 
#pragma GCC optimize("-fstrict-overflow") 
#pragma GCC optimize("-falign-functions") 
#pragma GCC optimize("-fcse-skip-blocks") 
#pragma GCC optimize("-fcse-follow-jumps") 
#pragma GCC optimize("-fsched-interblock") 
#pragma GCC optimize("-fpartial-inlining") 
#pragma GCC optimize("no-stack-protector") 
#pragma GCC optimize("-freorder-functions") 
#pragma GCC optimize("-findirect-inlining") 
#pragma GCC optimize("-fhoist-adjacent-loads") 
#pragma GCC optimize("-frerun-cse-after-loop") 
#pragma GCC optimize("inline-small-functions") 
#pragma GCC optimize("-finline-small-functions") 
#pragma GCC optimize("-ftree-switch-conversion") 
#pragma GCC optimize("-foptimize-sibling-calls") 
#pragma GCC optimize("-fexpensive-optimizations") 
#pragma GCC optimize("-funsafe-loop-optimizations") 
#pragma GCC optimize("inline-functions-called-once") 
#pragma GCC optimize("-fdelete-null-pointer-checks") 
using namespace std; 
char *p1,*p2,buf[1<<20]; 

#define GC (p1==p2&&(p1=buf,p2=buf+fread(buf,1,1<<20,stdin),p1==p2)?0:(*(p1++))) 
//#define GC getchar() 
inline int in() 
{ 
    int ans; 
    char t,k; 
    while(((t=GC)!='-'&&(t>'9'||t<'0'))); 
    k=(t=='-'); 
    ans=k?0:(t-'0'); 
    while((t=GC)>='0'&&t<='9')ans=ans*10+t-'0'; 
    return k?-ans:ans; 
}
const int maxn=100010;
struct node{
    int ls,rs;
    int sum;
};
int root[maxn];
struct tree{
    node t[maxn<<5];
    int tot=0;
    inline void build(int &rt,int l,int r)
    {
        rt=++tot;
        t[rt].sum=0;
        if(l==r)return;
        int mid=((l+r)>>1);
        build(t[rt].ls,l,mid);
        build(t[rt].rs,mid+1,r);
    }
    int updata(int x,int p,int l,int r){
        int rt=++tot;
        t[rt].ls=t[p].ls;
        t[rt].rs=t[p].rs;
        t[rt].sum=t[p].sum+1;
        if(l==r)return rt;
        int mid=((l+r)>>1);
        if(mid>=x)t[rt].ls=updata(x,t[rt].ls,l,mid);
        else t[rt].rs=updata(x,t[rt].rs,mid+1,r);
        return rt;
    }
    int gs(int x,int y,int l,int r,int k){
        int mid=((l+r)>>1);
        int tmp=t[t[y].ls].sum-t[t[x].ls].sum;
        if(l==r)return l;
        if(k<=tmp)return gs(t[x].ls,t[y].ls,l,mid,k);
        else return gs(t[x].rs,t[y].rs,mid+1,r,k-tmp);
    }
}tr;
int n,m;
int a[maxn],b[maxn];
int main()
{
    n=in();m=in();
    int i,j;
    for(i=1;i<=n;i++){
        a[i]=in();
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    int bs=unique(b+1,b+n+1)-b-1;
    tr.build(root[0],1,bs);
    for(i=1;i<=n;i++)
    {
        int pos=lower_bound(b+1,b+bs+1,a[i])-b;
        root[i]=tr.updata(pos,root[i-1],1,bs);
    }
    for(i=1;i<=m;i++)
    {
        int l,r,k;
        l=in();r=in();k=in();
        printf("%d\n",b[tr.gs(root[l-1],root[r],1,bs,k)]);
    }
    return 0;
}

?
动态
注:动态的主席树空间一定要开大,不然RE调一天都调不出来

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int lowbit(int x){return x&(-x);}
struct node{
    int sum,ls,rs;
};
const int maxn=500100;
int n,m;
int root1[maxn<<2];
int root[maxn<<2];
int a[maxn<<2],b[maxn<<2],bs;
int tl[maxn<<2],tr[maxn<<2];
struct tree{
    node sum[maxn<<6];
    int tot=0;
    void pushup(int p)
    {
        sum[p].sum=sum[sum[p].ls].sum+sum[sum[p].rs].sum;
    }
    void build(int &p,int l,int r)
    {
        p=++tot;
        if(l==r)return;
        int mid=((l+r)>>1);
        build(sum[p].ls,l,mid);
        build(sum[p].rs,mid+1,r);
//      pushup(p);
    }
    int ins(int x,int p,int l,int r,int k)
    {
        int p1=++tot;
        sum[p1].ls=sum[p].ls;
        sum[p1].rs=sum[p].rs;
        sum[p1].sum=sum[p].sum+k;
        if(l==r){
            return p1;
        }
        int mid=((l+r)>>1);
        if(x<=mid)sum[p1].ls=ins(x,sum[p].ls,l,mid,k);
        else sum[p1].rs=ins(x,sum[p].rs,mid+1,r,k);
//      pushup(p1);
        return p1;
    }
    void add(int x,int k)
    {
        int pos=lower_bound(b+1,b+bs+1,a[x])-b;
        while(x<=n){
            root[x]=ins(pos,root[x],1,bs,k);
            x+=lowbit(x);
        }
    }
    int r_gs(int x,bool f)
    {
        int res=0;
        while(x){
            if(f)res+=sum[sum[tr[x]].ls].sum;
            else res+=sum[sum[tl[x]].ls].sum;
            x-=lowbit(x);
        }
        return res;
    }
    int gs(int x,int y,int rx,int ry,int l,int r,int k)
    {
        if(l==r)return l;
        int mid=((l+r)>>1);
        int res=r_gs(y,1)-r_gs(x,0)+sum[sum[ry].ls].sum-sum[sum[rx].ls].sum;
        if(k<=res){
            int i;
            for(i=y;i;i-=lowbit(i))tr[i]=sum[tr[i]].ls;
            for(i=x;i;i-=lowbit(i))tl[i]=sum[tl[i]].ls;
            return gs(x,y,sum[rx].ls,sum[ry].ls,l,mid,k);
        }
        else {
            int i;
            for(i=y;i;i-=lowbit(i))tr[i]=sum[tr[i]].rs;
            for(i=x;i;i-=lowbit(i))tl[i]=sum[tl[i]].rs;
            return gs(x,y,sum[rx].rs,sum[ry].rs,mid+1,r,k-res);
        }
    }
}st;
struct actt{
    int x,y,k;
    bool ch;
}g[maxn<<2];
int main()
{
    int i,j;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=a[i];
        bs+=1;
    }
    for(i=1;i<=m;i++)
    {
        char cc;
        cin>>cc>>g[i].x;
        if(cc=='Q')cin>>g[i].y>>g[i].k,g[i].ch=1;
        else cin>>g[i].y,b[++bs]=g[i].y;
    }
    sort(b+1,b+bs+1);
    int tmp=unique(b+1,b+bs+1)-b-1;
    bs=tmp;
    b[0]=-233;
    st.build(root1[0],1,bs);
    for(i=1;i<=n;i++)root1[i]=st.ins(lower_bound(b+1,b+bs+1,a[i])-b,root1[i-1],1,bs,1);
    for(i=1;i<=n;i++)root[i]=root1[0];
    for(i=1;i<=m;i++)
    {
        if(g[i].ch){
            for(j=g[i].y;j;j-=lowbit(j))tr[j]=root[j];
            for(j=g[i].x-1;j;j-=lowbit(j))tl[j]=root[j];
            printf("%d\n",b[st.gs(g[i].x-1,g[i].y,root1[g[i].x-1],root1[g[i].y],1,bs,g[i].k)]);
        }
        else{
            st.add(g[i].x,-1);
            a[g[i].x]=g[i].y;
            st.add(g[i].x,1);
        }
    }
    return st.tot;
}

思路好想码量巨大警告

以上是关于我想要打一个主席树的主要内容,如果未能解决你的问题,请参考以下文章

[COGS 257]动态排名系统 树状数组套主席树

关于主席树

线段树+主席树笔记

bzoj2989&&4170数列——二进制分组+主席树

bzoj4448: [Scoi2015]情报传递

主席树算法解析