线段树代码整理

来源:互联网 发布:何方抢票软件 编辑:程序博客网 时间:2024/06/03 16:32

·      单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来

o   hdu1166敌兵布阵
题意:O(-1)
思路:O(-1)
线段树功能:update:单点增减 query:区间求和

/*************************************************************************> File Name: hdu1166.cpp> Author: FangPin> Mail: fangpin1993@hotmail.com> Created Time: 六  3/ 5 22:07:17 2016 ************************************************************************/#include<iostream>using namespace std;class SegmentTree{private:    int *a;    void pushup(int rt){        a[rt]=a[rt<<1]+a[rt<<1|1];    }public:    SegmentTree(int n){        a=new int[n<<2];    }    ~SegmentTree(){        delete[] a;    }    void build(int rt,int l,int r){        if(l==r){            scanf("%d",&a[rt]);            return ;        }        else{            int m=(l+r)>>1;            build(rt<<1,l,m);            build(rt<<1|1,m+1,r);            pushup(rt);        }    }    void update(int rt,int l,int r,int pos,int val){        if(l==r){            a[rt]+=val;            return;        }        int m=(l+r)>>1;        if(m>=pos)            update(rt<<1,l,m,pos,val);        else            update(rt<<1|1,m+1,r,pos,val);        pushup(rt);    }    int query(int rt,int l,int r,int x,int y){        if(x<=l && y>=r)            return a[rt];        int ans=0;        int m=(l+r)>>1;        if(x<=m)            ans+=query(rt<<1,l,m,x,y);        if(y>m)            ans+=query(rt<<1|1,m+1,r,x,y);        return ans;    }};int main(){    int t;    scanf("%d",&t);    for(int ca=0;ca<t;++ca){        int n;        scanf("%d",&n);        SegmentTree sum(n);        sum.build(1,1,n);        printf("Case %d:\n",ca+1);        char s[10];        while(scanf("%s",s),s[0]!='E'){            if(s[0]=='Q'){                int x,y;                scanf("%d%d",&x,&y);                printf("%d\n",sum.query(1,1,n,x,y));            }            else{                int pos,val;                scanf("%d%d",&pos,&val);                if(s[0]=='S')                    val=-val;                sum.update(1,1,n,pos,val);            }        }    }}

o   hdu1754 I Hate It
题意:O(-1)
思路:O(-1)
线段树功能:update:单点替换 query:区间最值

/*************************************************************************> File Name: hdu1754.cpp> Author: FangPin> Mail: fangpin1993@hotmail.com> Created Time: 日  3/ 6 21:24:47 2016 ************************************************************************/#include<iostream>#include <algorithm>#include <cstdio>using namespace std;class SegmentTree{private:    int *a;    void pushup(int rt){        a[rt]=max(a[rt<<1],a[rt<<1|1]);    }public:    SegmentTree(int n){        a=new int[n<<2];    }    ~SegmentTree(){        delete[] a;    }    void build(int rt,int l,int r){        if(l==r){            scanf("%d",a+rt);            return;        }        int m=(l+r)>>1;        build(rt<<1,l,m);        build(rt<<1|1,m+1,r);        pushup(rt);    }    void update(int rt,int l,int r,int pos,int val){        if(l==r){            a[rt]=val;            return ;        }        int m=(l+r)>>1;        if(m>=pos)            update(rt<<1,l,m,pos,val);        else            update(rt<<1|1,m+1,r,pos,val);        pushup(rt);    }    int query(int rt,int l,int r,int x,int y){        if(x<=l && y>=r)            return a[rt];        int m=(l+r)>>1;        int ans=-(1<<30);        if(x<=m)            ans=max(ans,query(rt<<1,l,m,x,y));        if(y>m)            ans=max(ans,query(rt<<1|1,m+1,r,x,y));        return ans;    }};int main(){    int n,m;    while(scanf("%d%d",&n,&m)==2){        SegmentTree st(n);        st.build(1,1,n);        char s[3];        int a,b;        for(int i=0;i<m;++i){            scanf("%s%d%d",s,&a,&b);            if(s[0]=='Q')                printf("%d\n",st.query(1,1,n,a,b));            else st.update(1,1,n,a,b);        }    }    return 0;}

o   hdu1394 Minimum Inversion Number
题意:求Inversion后的最小逆序数
思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解
线段树功能:update:单点增减 query:区间求和

/*************************************************************************> File Name: hdu1394.cpp> Author: FangPin> Mail: fangpin1993@hotmail.com> Created Time: 日  3/ 6 21:58:42 2016 ************************************************************************/#include<iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;class SegmentTree{private:    int *a;    void pushup(int rt){        a[rt]=a[rt<<1]+a[rt<<1|1];    }public:    SegmentTree(int n){        a=new int[n<<2];        memset(a,0,(n<<2)*sizeof(int));    }    ~SegmentTree(){        delete[] a;    }    void update(int rt,int l,int r,int pos){        if(l==r){            ++a[rt];            return;        }        int m=(l+r)>>1;        if(m>=pos)            update(rt<<1,l,m,pos);        else update(rt<<1|1,m+1,r,pos);        pushup(rt);    }    int query(int rt,int l,int r,int x,int y){        if(x<=l && y>=r)            return a[rt];        int m=(l+r)>>1;        int ans=0;        if(m>=x)            ans+=query(rt<<1,l,m,x,y);        if(y>m)            ans+=query(rt<<1|1,m+1,r,x,y);        return ans;    }};int data[5002];int main(){    int n;    while(~scanf("%d",&n)){        SegmentTree st(n);        int ret=0;        for(int i=1;i<=n;++i){            scanf("%d",data+i);            ++data[i];            st.update(1,1,n,data[i]);            ret+=st.query(1,1,n,data[i]+1,n);        }        int ans=ret;        for(int i=1;i<n;++i){            ret+=n+1-2*data[i];            ans=min(ans,ret);        }        printf("%d\n",ans);    }}

o   hdu2795 Billboard
题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子
思路:每次找到最大值的位子,然后减去L
线段树功能:query:区间求最大值的位子(直接把update的操作在query里做了)

/*************************************************************************> File Name: hdu2795.cpp> Author: FangPin> Mail: fangpin1993@hotmail.com> Created Time: 一  3/ 7 22:09:59 2016 ************************************************************************/#include <cstdio>#include<iostream>#include <algorithm>using namespace std;class SegmentTree{private:    int *a;    void pushup(int rt){        a[rt]=max(a[rt<<1],a[rt<<1|1]);    }public:    SegmentTree(int n,int w){        a=new int[n<<2];        for(int i=1;i<(n<<2);++i)            a[i]=w;    }    ~SegmentTree(){        delete[] a;    }    int query(int rt,int l,int r,int w){        if(l==r){            a[rt]-=w;            return l;        }        int m=(l+r)>>1;        int ans=(a[rt<<1]>=w)?query(rt<<1,l,m,w):query(rt<<1|1,m+1,r,w);        pushup(rt);        return ans;    }    int all_max()const{        return a[1];    }};int main(){    int h,w,n;    while(scanf("%d%d%d",&h,&w,&n)==3){        SegmentTree st(min(h,n),w);        for(int i=0;i<n;++i){            int x;            scanf("%d",&x);            if(st.all_max()<x) puts("-1");            else printf("%d\n",st.query(1,1,min(h,n),x));        }    }    return 0;}
poj 2828
</pre><pre code_snippet_id="1598774" snippet_file_name="blog_20160307_4_4006020" name="code" class="cpp">

/*************************************************************************> File Name: poj2828.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 2016年03月09日 星期三 22时01分29秒 ************************************************************************/#include<iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;class SegmentTree{private:    int *a,*b;    void pushup(int rt){        a[rt]=a[rt<<1]+a[rt<<1|1];    }public:    SegmentTree(int n){        a=new int[n<<2];        b=new int[n];    }    ~SegmentTree(){        delete[] a;    }    void build(int rt,int l,int r){        if(l==r){            a[rt]=1;            return ;        }        int m=(l+r)>>1;        build(rt<<1,l,m);        build(rt<<1|1,m+1,r);        pushup(rt);    }    void update(int rt,int l,int r,int pos,int val){        if(l==r){            a[rt]=0;            b[l]=val;            return;        }        int m=(l+r)>>1;        if(a[rt<<1]>=pos)            update(rt<<1,l,m,pos,val);        else            update(rt<<1|1,m+1,r,pos-a[rt<<1],val);        pushup(rt);    }    int getans(int pos)const{        return b[pos];    }};int b[200002],data[200002][2];int main(){    int t;    while(~scanf("%d",&t)){        SegmentTree st(t);        st.build(1,1,t);        for(int i=1;i<=t;++i)            scanf("%d%d",&data[i][0],&data[i][1]);        for(int i=t;i>0;--i)            st.update(1,1,t,data[i][0]+1,data[i][1]);        for(int i=1;i<t;++i)            printf("%d ",st.getans(i));        printf("%d\n",st.getans(t));    }    return 0;}


·      成段更新(通常这对初学者来说是一道坎),需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候

o   hdu1698 Just a Hook
题意:O(-1)
思路:O(-1)
线段树功能:update:成段替换 (由于只query一次总区间,所以可以直接输出1结点的信息)


/*************************************************************************> File Name: hdu1698.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 2016年03月11日 星期五 22时06分04秒 ************************************************************************/#include<iostream>#include <cstdio>#include <algorithm>using namespace std;class SegmentTree{private:    int *a;    int *lazy;    void pushup(int rt){        a[rt]=a[rt<<1]+a[rt<<1|1];    }    void pushdown(int rt,int len){        if(lazy[rt]){            lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];            a[rt<<1]=(len-(len>>1))*lazy[rt];            a[rt<<1|1]=(len>>1)*lazy[rt];            lazy[rt]=0;        }    }public:    SegmentTree(int n){        a=new int[n<<2];        lazy=new int[n<<2];        fill(lazy,lazy+(n<<2),0);    }    ~SegmentTree(){        delete []a;        delete []lazy;    }    void build(int rt,int l,int r){        if(l==r){            a[rt]=1;            return ;        }        int m=(l+r)>>1;        build(rt<<1,l,m);        build(rt<<1|1,m+1,r);        pushup(rt);    }    void update(int rt,int l,int r,int x,int y,int val){        if(x<=l && y>=r){            lazy[rt]=val;            a[rt]=(r-l+1)*val;            return;        }        pushdown(rt,r-l+1);        int m=(l+r)>>1;        if(x<=m)            update(rt<<1,l,m,x,y,val);        if(y>m)            update(rt<<1|1,m+1,r,x,y,val);        pushup(rt);    }    int ans()const{        return a[1];    }};int main(){    int t;    scanf("%d",&t);    for(int ca=1;ca<=t;++ca){        int n,m;        scanf("%d%d",&n,&m);        SegmentTree st(n);        st.build(1,1,n);        for(int i=0;i<m;++i){            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            st.update(1,1,n,a,b,c);        }        printf("Case %d: The total value of the hook is %d.\n",ca,st.ans());    }    return 0;}


o   poj3468 A Simple Problem with Integers
题意:O(-1)
思路:O(-1)
线段树功能:update:成段增减 query:区间求和


/*************************************************************************> File Name: poj3468.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 日  3/13 23:16:31 2016 ************************************************************************/#include<iostream>#include <cstdio>#include <cstring>using namespace std;class SegmentTree{private:    long long *a,*lazy;    void pushup(int rt){        a[rt]=a[rt<<1]+a[rt<<1|1];    }    void pushdown(int rt,int len){        if(lazy[rt]){            lazy[rt<<1]+=lazy[rt];            lazy[rt<<1|1]+=lazy[rt];            a[rt<<1]+=(len-(len>>1))*lazy[rt];            a[rt<<1|1]+=(len>>1)*lazy[rt];            lazy[rt]=0;        }    }public:    SegmentTree(int n){        a=new long long[n<<2];        lazy=new long long[n<<2];        memset(lazy,0,(n<<2)*sizeof(long long));    }    ~SegmentTree(){        delete[] a;        delete[] lazy;    }    void build(int rt,int l,int r){        if(l==r){            scanf("%lld",&a[rt]);            return ;        }        int m=(l+r)>>1;        build(rt<<1,l,m);        build(rt<<1|1,m+1,r);        pushup(rt);    }    void update(int rt,int l,int r,int x,int y,long long val){        if(x<=l && y>=r){            lazy[rt]+=val;            a[rt]+=(r-l+1)*val;            return;        }        int m=(l+r)>>1;        pushdown( rt, r-l+1);        if(x<=m)            update(rt<<1,l,m,x,y,val);        if(y>m)            update(rt<<1|1,m+1,r,x,y,val);        pushup(rt);    }    long long query(int rt,int l,int r,int x,int y){        if(x<=l && y>=r)            return a[rt];        pushdown(rt,r-l+1);        int m=(l+r)>>1;        long long ans=0;        if(x<=m)            ans+=query(rt<<1,l,m,x,y);        if(y>m)            ans+=query(rt<<1|1,m+1,r,x,y);        return ans;    }};int main(){    int n,m;    scanf("%d%d",&n,&m);    SegmentTree st(n);    st.build(1,1,n);    while(m--){        char s[3];        scanf("%s",s);        if(s[0]=='Q'){            int a,b;            scanf("%d%d",&a,&b);            printf("%lld\n",st.query(1,1,n,a,b));        }        else{            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            st.update(1,1,n,a,b,c);        }    }    return 0;}


  • poj1436Horizontally Visible Segments

  1. 对y轴进行建树,对每条线段按横轴从小到大排序,从第1条线段开始查询并更新 
  2. 查询该条线段所表示的区间内不同颜色数量(即可见线段数)并且记录可见线段,然后更新该区间颜色  
  3. 最后暴力求两两可见线段数量 
  4. 但是注意:0,4,1 和 0,2,2 和 3,4,2这三条线段覆盖的结果是区间0~4通过线段树查找可见线段是两条,其实是3条(2~3可见另一条) 
  5. 可以把查询更新的区间*2,比如上面数据变成0,8,1 和 0,4,2 和 6,8,2则4~6之间可见一条线段  



/*************************************************************************> File Name: 1436.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 五  3/18 21:57:58 2016 ************************************************************************/#include<iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <set>using namespace std;const int MAXN=8005;struct Node{    int y1,y2,x;}data[MAXN];//bool hash[MAXN];int lazy[MAXN<<3];bool lk[MAXN][MAXN];void build(){    memset(lazy,0,sizeof(lazy));}void pushdown(int rt){    if(lazy[rt]){        lazy[rt<<1]=lazy[rt];        lazy[rt<<1|1]=lazy[rt];        lazy[rt]=0;    }}void update(int rt,int l,int r,int x,int y,int val){    if(x<=l && y>=r){        lazy[rt]=val;        return ;    }    int m=(l+r)>>1;    pushdown(rt);    if(x<=m)        update(rt<<1,l,m,x,y,val);    if(y>m)        update(rt<<1|1,m+1,r,x,y,val);}void query(int rt,int l,int r,int x,int y,int pos){    if(lazy[rt]){        lk[lazy[rt]][pos]=true;        return;    }    if(l==r)        return ;    int m=(l+r)>>1;    pushdown(rt);    if(x<=m)        query(rt<<1,l,m,x,y,pos);    if(y>m)        query(rt<<1|1,m+1,r,x,y,pos);}void init(){    memset(lk,false,sizeof(lk));}bool cmp(const Node &a,const Node &b){    return a.x<b.x;}int main(){    int t,n;    scanf("%d",&t);    while(t--){        init();        int n;        scanf("%d",&n);        for(int i=0;i<n;++i){            scanf("%d%d%d",&data[i].y1,&data[i].y2,&data[i].x);            if(data[i].y1>data[i].y2)                swap(data[i].y1,data[i].y2);            data[i].y1*=2;            data[i].y2*=2;        }        sort(data,data+n,cmp);        build();        for(int i=0;i<n;++i){            query(1,1,MAXN<<1,data[i].y1,data[i].y2,i+1);            update(1,1,MAXN<<1,data[i].y1,data[i].y2,i+1);        }        int ans=0;       //. debug(n);        for(int i=1;i<=n;++i){            for(int j=i+1;j<=n;++j){                if(lk[i][j])                    for(int k=j+1;k<=n;++k){                        if(lk[i][k] && lk[j][k])                            ++ans;                    }            }        }        printf("%d\n",ans);    }}

·      区间合并
这类题目会询问区间中满足条件的连续最长区间,所以PushUp的时候需要对左右儿子的区间进行合并

o   poj3667 Hotel
题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边
2 a b:将[a,a+b-1]的房间清空
思路:记录区间中最长的空房间
线段树操作:update:区间替换 query:询问满足条件的最左断点


/*************************************************************************> File Name: poj3667.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 四  3/24 22:20:43 2016************************************************************************/#include<iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN=55555;int sum[MAXN<<2],lsum[MAXN<<2],rsum[MAXN<<2],lazy[MAXN<<2];void pushup(int rt,int len){    lsum[rt]=(lsum[rt<<1]==len-(len>>1))?lsum[rt<<1]+lsum[rt<<1|1]:lsum[rt<<1];    rsum[rt]=(rsum[rt<<1|1]==(len>>1))?rsum[rt<<1|1]+rsum[rt<<1]:rsum[rt<<1|1];    sum[rt]=max(max(sum[rt<<1],sum[rt<<1|1]),rsum[rt<<1]+lsum[rt<<1|1]);}void build(int rt,int l,int r){    sum[rt]=lsum[rt]=rsum[rt]=r-l+1;    lazy[rt]=-1;    if(l==r)    return;    int m=(l+r)>>1;    build(rt<<1,l,m);    build(rt<<1|1,m+1,r);}void pushdown(int rt,int m){ if (lazy[rt] != -1) {lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];sum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = lazy[rt] ? 0 : m - (m >> 1);sum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = lazy[rt] ? 0 : (m >> 1);lazy[rt] = -1;}}int query(int rt,int l,int r,int x){    if(l==r) return l;    pushdown(rt,r-l+1);    int m=(l+r)>>1;    if(sum[rt<<1]>=x) return query(rt<<1,l,m,x);    else if(rsum[rt<<1]+lsum[rt<<1|1]>=x) return m-rsum[rt<<1]+1;    else return query(rt<<1|1,m+1,r,x);}void update(int rt,int l,int r,int x,int y,int val){    if(x<=l && y>=r){        lazy[rt]=val;        sum[rt]=lsum[rt]=rsum[rt]=val?0:r-l+1;        return;    }    pushdown(rt,r-l+1);    int m=(r+l)>>1;    if(x<=m)    update(rt<<1,l,m,x,y,val);    if(y>m)    update(rt<<1|1,m+1,r,x,y,val);    pushup(rt,r-l+1);}int main(){    int n,m;    while(~scanf("%d%d",&n,&m)){        build(1,1,n);        for(int i=0;i<m;++i){            int op,x,y;            scanf("%d",&op);            if(op==1){                scanf("%d",&x);                if(sum[1]<x) puts("0");                else{                    int ans=query(1,1,n,x);                    printf("%d\n",ans);                    update(1,1,n,ans,ans+x-1,1);                }            }            else{                scanf("%d%d",&x,&y);                update(1,1,n,x,x+y-1,0);            }        }    }    return 0;}



HDU3308-LCIS-线段树区间合并

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308

题目大意:给n个数,两种操作

                  1:U  a,b   更新第a个为b (从0开始)

                  2:Q  a,b  查询 a,b之间LCIS(最长连续递增子序列)的长度。

其实也可以说是个模板题;三个变量保存数据ls,rs,ms分别保存从左端点开始的最长连续上升子序列,从右端点开始的最长连续上升子序列,以及这个区间的最长连续上升子序列;唯一不同的就是这里得判断一下是否能够合并;即增加一个比较如果num[mid]<num[mid+1](num数组保存的是输入的数据


/*************************************************************************> File Name: hdu3308.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 日  3/27 21:47:12 2016 ************************************************************************/#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN=100002;int data[MAXN];int a[MAXN<<2],la[MAXN<<2],ra[MAXN<<2];void pushup(int rt,int l,int r){    int m=(l+r)>>1;    la[rt]=la[rt<<1];    if(la[rt]==m-l+1 && data[m]<data[m+1])        la[rt]+=la[rt<<1|1];    ra[rt]=ra[rt<<1|1];    if(ra[rt]==r-m && data[m]<data[m+1])        ra[rt]+=ra[rt<<1];    a[rt]=max(a[rt<<1],a[rt<<1|1]);    if(data[m]<data[m+1])    a[rt]=max(a[rt],ra[rt<<1]+la[rt<<1|1]);}void build(int rt,int l,int r){    if(l==r){        a[rt]=la[rt]=ra[rt]=1;        return;    }    int m=(l+r)>>1;    build(rt<<1,l,m);    build(rt<<1|1,m+1,r);    pushup(rt,l,r);}void update(int rt,int l,int r,int pos){    if(l==r){        return ;    }    int m=(l+r)>>1;    if(pos<=m)        update(rt<<1,l,m,pos);    else if(pos>m)        update(rt<<1|1,m+1,r,pos);    pushup(rt,l,r);}int query(int rt,int l,int r,int x,int y){    if(x<=l && y>=r){        return a[rt];    }    int m=(l+r)>>1;    int ans=0;    if(x<=m)        ans=max(ans,query(rt<<1,l,m,x,y));    if(y>m)        ans=max(ans,query(rt<<1|1,m+1,r,x,y));    if(x<=m && y>m && data[m]<data[m+1])        ans=max(ans,min(m-x+1,ra[rt<<1])+min(y-m,la[rt<<1|1]));    return ans;}int main(){    int t;    scanf("%d",&t);    while(t--){        int n,m;        scanf("%d%d",&n,&m);        for(int i=1;i<=n;++i){            scanf("%d",&data[i]);        }        build(1,1,n);        char s[10];        int x,y;        for(int i=0;i<m;++i){            scanf("%s%d%d",s,&x,&y);            if(s[0]=='Q'){                printf("%d\n",query(1,1,n,x+1,y+1));            }            else{                data[x+1]=y;                update(1,1,n,x+1);            }        }    }}



1 0
原创粉丝点击