数据结构模板

来源:互联网 发布:美国人口增长 知乎 编辑:程序博客网 时间:2024/06/07 19:33

以下数据类型均以double作为value_type,使用时根据实际情况修改为其他类型。

二叉索引树

struct FenwickTree:vector<double>{    explicit FenwickTree(int k)//默认初始化一个能保存k个元素的空树状数组    {        assign(k+1,0);//有效下标从1开始,0仅作逻辑用处    }    int lowbit(int k)    {        return k&-k;//也可写作x&(x^(x–1))    }    double sum(int k)//求第1个元素到第k个元素的和    {        if(k<=0)return 0;        return sum(k-lowbit(k))+(*this)[k];    }    double query(int l,int r)//区间求和    {        return sum(r)-sum(l-1);    }    void add(int k,double w)//为节点k加上w    {        if(k>=size())return;        (*this)[k]+=w;        add(k+lowbit(k),w);    }};

静态RMQ

struct SparseTable_RMQ {    vector<vector<double> > d;    SparseTable_RMQ(const vector<double> &v)    {        d.assign(v.size(),vector<double>());        for(int i=0; i!=v.size(); ++i)            d[i].push_back(v[i]);        for(int j=0; (1<<j)<=v.size(); ++j)            for(int i=0; (1<<j)+i-1<v.size(); ++i)                d[i].push_back(min(d[i][j-1],                                   d[i+(1<<j-1)][j-1]));    }    double query(int l,int r)    {        int k=0;        while((1<<k+1)<=r-l+1)            ++k;        return min(d[l][k],d[r-(1<<k)+1][k]);    }};

线段树

区间增加

struct SegTree1{    vector<double> sumv,minv,addv;    double inf=1e9,_min,_sum;    int last;    explicit SegTree1(int _n)    {        last=_n;//有效下标从1开始,0仅作逻辑用处        addv.assign(2*last,0);        sumv.assign(2*last,0);        minv.assign(2*last,inf);    }    void add(int pl,int pr,double pv)    {        add(pl,pr,pv,1,1,last);    }    void query(int ql,int qr)    {        _sum=0;        _min=inf;        query(ql,qr,0,1,1,last);    }    void add(int pl,int pr,double pv,             int k,int l,int r)    {        if(pl<=l&&r<=pr)            addv[k]+=pv;        else        {            int lc=k*2,rc=k*2+1,m=l+(r-l)/2;            if(pl<=m)add(pl,pr,pv,lc,l,m);            if(m<pr)add(pl,pr,pv,rc,m+1,r);        }        maintain(k,l,r);    }    void query(int ql,int qr,double add,//当前所有节点祖先add之和               int k,int l,int r)    {        if(ql<=l&&r<=qr)        {            _sum+=sumv[k]+add*(r-l+1);            _min=min(_min,minv[k]+add);            return;        }        int lc=k*2,rc=k*2+1,m=l+(r-l)/2;        if(ql<=m)query(ql,qr,add+addv[k],lc,l,m);        if(m<qr)query(ql,qr,add+addv[k],rc,m+1,r);    }    void maintain(int k,int l,int r)//维护节点k    {        minv[k]=addv[k];        sumv[k]=addv[k]*(r-l+1);        if(r>l)        {            int lc=k*2,rc=k*2+1;            sumv[k]+=sumv[lc]+sumv[rc];            minv[k]+=min(minv[lc],minv[rc]);        }    }};

区间修改

struct SegTree2{    vector<double> sumv,minv,setv;    double inf=1e9,_min,_sum;    int last;    explicit SegTree2(int _n)    {        last=_n;//有效下标从1开始,0仅作逻辑用处        setv.assign(2*last,inf);        sumv.assign(2*last,0);        minv.assign(2*last,inf);    }    void update(int pl,int pr,double pv)    {        return update(pl,pr,pv,1,1,last);    }    void query(int ql,int qr)    {        _sum=0;        _min=inf;        query(ql,qr,1,1,last);    }    void update(int pl,int pr,double pv,                int k,int l,int r)    {        if(pl<=l&&r<=pr)            setv[k]=pv;        else        {            int lc=k*2,rc=k*2+1,m=l+(r-l)/2;            if(setv[k]!=inf)//结点有标记,向下传递            {                setv[lc]=setv[rc]=setv[k];                setv[k]=inf;//清除本节点标记            }            if(pl<=m)update(pl,pr,pv,lc,l,m);            else maintain(lc,l,m);            if(m<pr)update(pl,pr,pv,rc,m+1,r);            else maintain(rc,m+1,r);        }        maintain(k,l,r);    }    void query(int ql,int qr,               int k,int l,int r)    {        if(setv[k]!=inf)//递归边界1:有set标记        {            _sum+=setv[k]*(min(r,qr)-max(l,ql)+1);            _min=min(_min,setv[k]);        }        else if(ql<=l&&r<=qr)//递归边界2:边界区间,没有被set操作影响        {            _sum+=sumv[k];            _min=min(_min,minv[k]);        }        else        {            int lc=k*2,rc=k*2+1,m=l+(r-l)/2;            if(ql<=m)query(ql,qr,lc,l,m);            if(m<qr)query(ql,qr,rc,m+1,r);        }    }    void maintain(int k,int l,int r)//维护节点k    {        minv[k]=setv[k];        sumv[k]=setv[k]*(r-l+1);        if(r>l)        {            int lc=k*2,rc=k*2+1;            sumv[k]+=sumv[lc]+sumv[rc];            minv[k]+=min(minv[lc],minv[rc]);        }    }};