zkw线段树

记录一个菜逼的成长。。

网上好多zkw线段树版本都是错的。。坑啊。
主要是连zkw的ppt上都是不完整和有错误的。统计的力量

结点信息

struct Node{
  int sum,mx,mn;
}T[maxn<<2];
int M,a[maxn];

建树

void build(int n)
{
  for( M = 1; M <= n+1; M <<= 1);
  for( int i = M + 1; i <= M + n; i++ )T[i].sum = T[i].mx = T[i].mn = a[i-M];
  for( int i = M - 1; i; i-- ){
    T[i].sum = T[i<<1].sum + T[i<<1|1].sum;

    //结点记录的是相对的值
    T[i].mx = max(T[i<<1].mx,T[i<<1|1].mx);
    T[i<<1].mx -= T[i].mx;T[i<<1|1].mx -= T[i].mx;

    T[i].mn = min(T[i<<1].mn,T[i<<1|1].mn);
    T[i<<1].mn -= T[i].mn;T[i<<1|1].mn -= T[i].mn;
  }
}

和的单点更新

for( T[x+=M].sum += v,x >>= 1; x; x >>= 1){
  T[x].sum = T[x<<1].sum + T[x<<1|1].sum;
}

最小(大)值的区间更新

区间更新也可以时单点更新(左端点等于右端点时

int s,t;
// 只更新到当s,t是兄弟结点时
for( s = x+M-1,t = x+M+1; s^t^1; s>>=1,t>>=1 ){
  if(~s&1)T[s^1].mx += v,T[s^1].mn += v;
  if( t&1)T[t^1].mx += v,T[t^1].mn += v;

  A = max(T[s].mx,T[s^1].mx);T[s].mx -= A;T[s^1].mx -= A;T[s>>1].mx += A;
  A = max(T[t].mx,T[t^1].mx);T[t].mx -= A;T[t^1].mx -= A;T[t>>1].mx += A;

  A = min(T[s].mn,T[s^1].mn);T[s].mn -= A;T[s^1].mn -= A;T[s>>1].mn += A;
  A = min(T[t].mn,T[t^1].mn);T[t].mn -= A;T[t^1].mn -= A;T[t>>1].mn += A;
  }

  // 更新到根
  while(s>1){
    A = max(T[s].mx,T[s^1].mx),T[s].mx -= A,T[s^1].mx -= A,T[s>>1].mx += A;

    A = min(T[s].mn,T[s^1].mn),T[s].mn -= A,T[s^1].mn -= A,T[s>>=1].mn += A;
  }

和的区间查询

int querySum(int l,int r,int res = 0)//查询闭区间[l,r]
{
  // 看成开区间(l-1,r+1)
  for( l = l + M - 1,r = r + M + 1; l^r^1; l >>= 1,r >>= 1 ){
    if(~l&1)res += T[l^1].sum;
    if( r&1)res += T[r^1].sum;
  }
  return res;
}

最小(大)值的区间查询

int queryMax(int l,int r,int lmx = 0,int rmx = 0)// 查询闭区间[l,r]
{
  // 这里还是闭区间[l,r],跟和的查询不同
  // 还要分是不是叶子结点
  l += M,r += M;
  int res ;
  if(l != r){
    for( ; l^r^1; l >>= 1,r >>= 1 ){
      lmx += T[l].mx;rmx += T[r].mx;
      if(~l&1)lmx = max(lmx,T[l^1].mx);
      if( r&1)rmx = max(rmx,T[r^1].mx); 
    }
  }
  res = max(lmx+T[l].mx,rmx+T[r].mx);
  while(l > 1)res += T[l>>=1].mx;
  return res;
}
int queryMin(int l,int r,int lmn = 0,int rmn = 0)
{
  l += M,r += M;
  int res = 0;
  if(l != r){
    for( ; l^r^1; l >>= 1,r >>= 1 ){
      lmn += T[l].mn;rmn += T[r].mn;
      if(~l&1)lmn = min(lmn,T[l^1].mn);
      if( r&1)rmn = min(rmn,T[r^1].mn); 
    }
  }
  res = min(lmn+T[l].mn,rmn+T[r].mn);
  while(l > 1)res += T[l>>=1].mn;
  return res;
}

完整模板

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 10;
struct Node{
  int sum,mx,mn;
}T[maxn<<2];
int M,a[maxn];
void build(int n)
{
  for( M = 1; M <= n+1; M <<= 1);
  for( int i = M + 1; i <= M + n; i++ )T[i].sum = T[i].mx = T[i].mn = a[i-M];
  for( int i = M - 1; i; i-- ){
    T[i].sum = T[i<<1].sum + T[i<<1|1].sum;

    T[i].mx = max(T[i<<1].mx,T[i<<1|1].mx);
    T[i<<1].mx -= T[i].mx;T[i<<1|1].mx -= T[i].mx;

    T[i].mn = min(T[i<<1].mn,T[i<<1|1].mn);
    T[i<<1].mn -= T[i].mn;T[i<<1|1].mn -= T[i].mn;
  }
}
void update(int x,int v,int A = 0)
{
  int s,t;
  for( s = x+M-1,t = x+M+1; s^t^1; s>>=1,t>>=1 ){
    if(~s&1)T[s^1].mx += v,T[s^1].mn += v;
    if( t&1)T[t^1].mx += v,T[t^1].mn += v;
    A = max(T[s].mx,T[s^1].mx);T[s].mx -= A;T[s^1].mx -= A;T[s>>1].mx += A;
    A = max(T[t].mx,T[t^1].mx);T[t].mx -= A;T[t^1].mx -= A;T[t>>1].mx += A;

    A = min(T[s].mn,T[s^1].mn);T[s].mn -= A;T[s^1].mn -= A;T[s>>1].mn += A;
    A = min(T[t].mn,T[t^1].mn);T[t].mn -= A;T[t^1].mn -= A;T[t>>1].mn += A;
  }

  while(s>1){
    A = max(T[s].mx,T[s^1].mx),T[s].mx -= A,T[s^1].mx -= A,T[s>>1].mx += A;

    A = min(T[s].mn,T[s^1].mn),T[s].mn -= A,T[s^1].mn -= A,T[s>>=1].mn += A;
  }

  for( T[x+=M].sum += v,x >>= 1; x; x >>= 1){
    T[x].sum = T[x<<1].sum + T[x<<1|1].sum;
  }
}
int querySum(int l,int r,int res = 0)
{
  for( l = l + M - 1,r = r + M + 1; l^r^1; l >>= 1,r >>= 1 ){
    if(~l&1)res += T[l^1].sum;
    if( r&1)res += T[r^1].sum;
  }
  return res;
}
int queryMax(int l,int r,int lmx = 0,int rmx = 0)
{
  l += M,r += M;
  int res ;
  if(l != r){
    for( ; l^r^1; l >>= 1,r >>= 1 ){
      lmx += T[l].mx;rmx += T[r].mx;
      if(~l&1)lmx = max(lmx,T[l^1].mx);
      if( r&1)rmx = max(rmx,T[r^1].mx); 
    }
  }
  res = max(lmx+T[l].mx,rmx+T[r].mx);
  while(l > 1)res += T[l>>=1].mx;
  return res;
}
int queryMin(int l,int r,int lmn = 0,int rmn = 0)
{
  l += M,r += M;
  int res = 0;
  if(l != r){
    for( ; l^r^1; l >>= 1,r >>= 1 ){
      lmn += T[l].mn;rmn += T[r].mn;
      if(~l&1)lmn = min(lmn,T[l^1].mn);
      if( r&1)rmn = min(rmn,T[r^1].mn); 
    }
  }
  res = min(lmn+T[l].mn,rmn+T[r].mn);
  while(l > 1)res += T[l>>=1].mn;
  return res;
}
int main()
{

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值