模板:线段树

来源:互联网 发布:python 均线策略 编辑:程序博客网 时间:2024/06/16 11:56
/*单点更新,区间求和*//*应用:1.建空树,可以查询比某值大的数之和,然后单点更新*/#define N 50050  int num[N];  struct Tree{        int l;      int r;      int sum;  }tree[4*N];    void build(int t,int l,int r){      tree[t].l=l;      tree[t].r=r;      if(tree[t].l==tree[t].r){          tree[t].sum=num[l];          return;      }      int mid=(l+r)/2;      build(2*t,l,mid);      build(2*t+1,mid+1,r);      tree[t].sum=tree[2*t].sum+tree[2*t+1].sum;}  void update(int t,int pos,int val){      if(tree[t].l==tree[t].r){          tree[t].sum=val;          return;      }      int mid=(tree[t].l+tree[t].r)/2;      if(pos<=mid)             /*这点注意,我们都把mid放到左边了*/          update(2*t,pos,val);      else          update(2*t+1,pos,val);      tree[t].sum=tree[2*t].sum+tree[2*t+1].sum;}  int query(int t,int l,int r){      if(l<=tree[t].l&&r>=tree[t].r)          return tree[t].sum;      int mid=(tree[t].l+tree[t].r)/2,ans=0;      if(l<=mid) ans+=query(2*t,l,r);/*加完左边加上右边的,不用分情况考虑*/      if(r>mid)  ans+=query(2*t+1,l,r);    return ans;  }  /*单点更新,区间最值*/void build(int t,int l,int r){      tree[t].l=l;      tree[t].r=r;      if(l==r){          tree[t].max=num[l];          return;      }      int mid=(l+r)/2;      build(2*t,l,mid);      build(2*t+1,mid+1,r);      tree[t].max=Max(tree[2*t].max,tree[2*t+1].max);  }    void update(int t,int pos,int x){      if(tree[t].l==tree[t].r){          tree[t].max=x;          return;      }      int mid=(tree[t].l+tree[t].r)/2;      if(pos<=mid){          update(2*t,pos,x);      }      else          update(2*t+1,pos,x);      tree[t].max=Max(tree[2*t].max,tree[2*t+1].max);  }    int query(int t,int l,int r){      if(l<=tree[t].l&&r>=tree[t].r)          return tree[t].max;      int s;      if(r<=tree[2*t].r)          s=query(2*t,l,r);      else if(l>=tree[2*t+1].l)          s=query(2*t+1,l,r);      else s=Max(query(2*t,l,tree[2*t].r),query(2*t+1,tree[2*t+1].l,r));      return s;  }  

区间更新,区间求和(延迟标记)

#define ll long longconst int maxn = 111111;ll num[maxn<<2];struct Tree{    int l,r;    ll sum;}tree[maxn<<2];ll lazy[maxn<<2];void down(int t, int len){    if(lazy[t]){        lazy[t<<1] += lazy[t];        lazy[t<<1|1] += lazy[t];/*延迟标记往下传*/        tree[t<<1].sum += lazy[t] * (len-(len>>1));/*左子树比右子树多1*/        tree[t<<1|1].sum += lazy[t] * (len>>1);        lazy[t] = 0;   /*往下传完就赋0*/    }}void build(int l,int r,int t){    tree[t].l=l; tree[t].r=r;    lazy[t]=0;    if(l==r){        tree[t].sum=num[l];        return;    }    int mid=(l+r)>>1;    build(l,mid,t<<1);    build(mid+1,r,t<<1|1);    tree[t].sum=tree[2*t].sum+tree[2*t+1].sum;}void update(int x,int l,int r,int t){    if(l<=tree[t].l&&r>=tree[t].r){        lazy[t]+=x;        tree[t].sum+=(ll)x*(tree[t].r-tree[t].l+1);        return;    }    down(t,tree[t].r-tree[t].l+1);    int mid=(tree[t].l+tree[t].r)>>1;    if(l<=mid) update(x,l,r,t<<1);    if(r>mid)  update(x,l,r,t<<1|1);    tree[t].sum=tree[2*t].sum+tree[2*t+1].sum;}ll query(int l,int r,int t){    if(l<=tree[t].l&&r>=tree[t].r) return tree[t].sum;    down(t,tree[t].r-tree[t].l+1);    int mid=(tree[t].l+tree[t].r)>>1; ll ans=0;    if(l<=mid) ans+=query(l,r,2*t);/*加完左边加上右边的,不用分情况考虑*/    if(r>mid)  ans+=query(l,r,2*t+1);    return ans;}
更新节点,区间合并(push_up)

const int N=100005;int n,m,s[N];struct Tree{      int l,r,c;//左右边界与连续的长度      int ln,rn;//左右边界的值      int ls,rs,ms;//左右最大LCIS,和区间最大LCIS  }tree[4*N];    void push_up(int i){      tree[i].ls = tree[2*i].ls;      tree[i].rs = tree[2*i+1].rs;      tree[i].ln = tree[2*i].ln;      tree[i].rn = tree[2*i+1].rn;      tree[i].ms = max(tree[2*i].ms,tree[2*i+1].ms);      if(tree[2*i].rn<tree[2*i+1].ln){  //如果左子树的右边界值小于右子树的左边界值,要合并左子树的右边界和右子树的左边界          if(tree[2*i].ls == tree[2*i].c)              tree[i].ls+=tree[2*i+1].ls;          if(tree[2*i+1].rs == tree[2*i+1].c)              tree[i].rs+=tree[2*i].rs;          tree[i].ms = max(tree[i].ms,tree[2*i].rs+tree[2*i+1].ls);      }  }  void build(int t,int l,int r){      tree[t].l=l;      tree[t].r=r;      tree[t].c=r-l+1;      if(l==r){          tree[t].ln=tree[t].rn=s[l];          tree[t].ls=tree[t].rs=tree[t].ms=1;          return;      }      int mid=(l+r)>>1;      build(2*t,l,mid);      build(2*t+1,mid+1,r);      push_up(t);  }  void update(int t,int pos,int val){      if(tree[t].l==tree[t].r){          tree[t].ln=tree[t].rn=val;          return;      }      int mid=(tree[t].l+tree[t].r)>>1;      if(pos<=mid)          update(2*t,pos,val);      else          update(2*t+1,pos,val);      push_up(t);   //向上维护  }  int query(int t,int l,int r){      if(l<=tree[t].l&&r>=tree[t].r)          return tree[t].ms;      int mid=(tree[t].l+tree[t].r)>>1,ans=0;      if(l<=mid) ans=max(ans,query(2*t,l,r));      if(r>mid)  ans=max(ans,query(2*t+1,l,r));      if(tree[2*t].rn < tree[2*t+1].ln)          ans=max(ans, min(mid-l+1,tree[2*t].rs) + min(r-mid,tree[2*t+1].ls));      //不能超过边界啊,所以右边要小于r-mid,左边同理。      return ans;  }  
区间合并(up and down)

/*lsum数组表示该段rt区间的左连续区间的最大值rsum数组表示该段rt区间的右连续区间的最大值msum数组表示该段区间的连续区间的最大值,可以是左连续、右连续、也可以使中间连续lazy数组表示懒惰标记,-1时表示未打上懒惰标记,不需要改变,0时表示该区间打上了区间被使用,1表示该区间被回收*/const int maxn = 5e4+5;  int msum[maxn<<2],lsum[maxn<<2],rsum[maxn<<2];  int lazy[maxn<<2];  void up(int l,int r,int rt){      int mid=(l+r)>>1;      lsum[rt]=lsum[rt<<1];      rsum[rt]=rsum[rt<<1|1];      if(lsum[rt<<1]==mid-l+1) lsum[rt]+=lsum[rt<<1|1];      if(rsum[rt<<1|1]==r-mid) rsum[rt]+=rsum[rt<<1];      msum[rt]=max(rsum[rt<<1]+lsum[rt<<1|1],max(msum[rt<<1],msum[rt<<1|1]));  }  void down(int l,int r,int rt){      if(lazy[rt]!=-1){          int mid=(l+r)>>1;          lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];          msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=lazy[rt]?mid-l+1:0;          msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=lazy[rt]?r-mid:0;          lazy[rt]=-1;      }  }  void build(int l,int r,int rt){      lazy[rt]=-1;      msum[rt]=lsum[rt]=rsum[rt]=r-l+1;      if(l==r) return;      int mid=(l+r)>>1;      build(l,mid,rt<<1);      build(mid+1,r,rt<<1|1);  }  void update(int L,int R,int k,int l,int r,int rt){      if(L<=l&&r<=R){          lazy[rt]=k;          msum[rt]=lsum[rt]=rsum[rt]=k?r-l+1:0;          return;      }      down(l,r,rt);      int mid=(l+r)>>1;      if(L<=mid) update(L,R,k,l,mid,rt<<1);      if(R>mid)update(L,R,k,mid+1,r,rt<<1|1);      up(l,r,rt);  }  int query(int len,int l,int r,int rt){      if(l==r) return l;      down(l,r,rt);      int mid=(l+r)>>1;      if(msum[rt<<1]>=len) return query(len,l,mid,rt<<1);      else if(rsum[rt<<1]+lsum[rt<<1|1]>=len) return mid-rsum[rt<<1]+1;      else return query(len,mid+1,r,rt<<1|1);  }