关于线段数自我总结

线段树

FIRST:

线段树是干嘛用的
给定n个数,支持操作:
①单点修改,单点查询。
②区间修改,单点查询。
③单点修改,区间查询。
④区间修改,区间查询。
时间复杂度要求小于n^2。


动态开点

void update (int &root,int l,int r,int t,int x) //当前节点编号,当前节点对应的区间,要修改的叶子结点编号,增加的值 { if (!root) root=++cnt; 
  sum[root]+=x; if (l==r) return; int mid=(l+r)/2; if (t<=mid) update(L[root],l,mid,t,x); else update(R[root],mid+1,r,t,x);
} //Ex1

//update(root,1,9,5,3) //这棵线段树的叶子结点总共有9个,把第5个叶子增3 update(root,1,9,4,4)

1.如何查询?

int query (int &root,int l,int r,int x,int y) //当前节点在root,root对应的区间是[l,r],要查[x,y]的和 { if (l==x && r==y) return sum[root]; int mid=(l+r)/2,suml=0,sumr=0; if (x<=mid) suml=query(L[root],l,mid,x,min(mid,y)); //要查的区间的左端点被左儿子区间包含的时候  if (y>mid) sumr=query(R[root],mid+1,r,max(mid+1,x),y); return suml+sumr;
} 
//cout<<query(root,1,9,3,5) //查询[3,5]的和

问题2

区间修改,单点查询如何进行区间操作?
答:lazy tag!

void update (int &root,int l,int r,int p,int q,int x) //当前节点编号,当前节点对应的区间,要修改的区间编号,增加的值  { if (!root) root=++cnt; 
     sum[root]+=x*(l~r 和 p~q的交); if (l==p && r==q) {tag[root]+=x; return;} int mid=(l+r)/2; if (p<=mid) update(L[root],l,mid,p,min(q,mid),x); if (q>mid) update(R[root],mid+1,r,max(mid+1,p),q,x);
}
//update(root,1,9,5,7,3) //这棵线段树的叶子结点总共有9个,把编号为5~7个叶子增3

如何查询?

int query (int &root,int l,int r,int x,int y) // 当前节点在root,root对应的区间是[l,r],要查[x,y]的和  { if (l==x && r==y) return sum[root];
    Down(root,l,r); int mid=(l+r)/2,suml=0,sumr=0; if (x<=mid) suml=query(L[root],l,mid,x,min(mid,y)); //要查的区间的左端点被左儿子区间包含的时候   if (y>mid) sumr=query(R[root],mid+1,r,max(mid+1,x),y); return suml+sumr;
}
    // cout<<query(root,1,9,3,5); //查询[3,5]的和  int Down(int x,int l,int r) //为x的节点,x的区间是[l,r],进行标记下传  { if (!L[x]) L[x]=++cnt; if (!R[x]) R[x]=++cnt;
    tag[L[x]] += tag[x];  tag[R[x]] += tag[x];
    sum[L[x]] += tag[x] * (左儿子节点个数);
    sum[R[x]] += tag[x] * (..);
    tag[x]=0;
}

全部评论

相关推荐

评论
点赞
收藏
分享
牛客网
牛客企业服务