求区间和;
LL sum[maxn<<2];//保存区间和
LL add[maxn<<2];//懒惰标记
LL a[maxn];//用于输入保存数据
求区间和的函数:
void pushup(int x)
{
sum[x]=sum[x<<1]+sum[x<<1|1];
}
建立线段树:
void buildtree(int l,int r,int rt)
{
if(l==r){
sum[rt]=a[l];//叶子节点的插入
return ;
}
int m=(l+r)>>1;
buildtree(l,m,rt<<1);//建立左子树
buildtree(m+1,r,rt<<1|1);//右子树
pushup(rt);//维护各区间的加和
}
单点修改:
void singlemodify(int X,int L,int l,int r,int rt)
{
if(l==r){
//a[L]+=X;
sum[rt]+=X;
return ;
}
int m=(l+r)>>1;
if(m>L){
singlemodify(X,L,l,m,rt<<1);//查询左边
}
else singlemodify(X,L,m+1,r,rt<<1|1);//查询右边
pushup(rt);//更新区间
}
区间修改:
void qmodify(int X,int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R){
sum[rt]+=(r-l+1)*X;
add[rt]+=X;
return ;
}
int m=(l+r)>>1;
pushdown(r-m,m-l+1,rt);
if(m>=L) qmodify(X,L,R,l,m,rt<<1);
if(R>m) qmodify(X,L,R,m+1,r,rt<<1|1);
pushup(rt);
}
延时标记函数
void pushdown(int rn,int ln,int rt)
{//对于有标记的节点,说明该节点之后的节点没有修改
if(add[rt]){
sum[rt<<1]+=ln*add[rt];
sum[rt<<1|1]+=rn*add[rt];
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
add[rt]=0;
}
return ;
}
查询:
LL query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R){
return sum[rt];
}
int m=(l+r)>>1;
pushdown(r-m,m-l+1,rt);//注意标记下推,因为可能会查询到未修改的节点
LL ans=0;
if(m>=L) ans+=query(L,R,l,m,rt<<1);
if(m<R) ans+=query(L,R,m+1,r,rt<<1|1);
return ans;
}
线段树区间合并类的做法
例题hdu1540
#include <bits/stdc++.h>
using namespace std;
int n,m;
#define maxx 50010
struct node
{
int l,r,ls,rs,ms;//ls是左端最长连续1区间,rs是右端最长连续1区间,ms是l-r区间内最长连续1区间
}sum[maxx<<2];
void pushup(int rt)
{
sum[rt].ls=sum[rt<<1].ls;//首先用子树的ls,rs更新根结点的
sum[rt].rs=sum[rt<<1|1].rs;
sum[rt].ms=max(max(sum[rt<<1].ms,sum[rt<<1|1].ms),sum[rt<<1].rs+sum[rt<<1|1].ls);//利用左右子树的ls,rs,ms求根的ms。
//下面的代码和上面的不能互换位置
if(sum[rt<<1].ls==sum[rt<<1].r-sum[rt<<1].l+1){//如果左子树满了,则要加上右子树的左边区间,因为左右子树管辖的区间是相邻的
sum[rt].ls+=sum[rt<<1|1].ls;//更新这个是为了更新比rt更上层的结点
}
if(sum[rt<<1|1].rs==sum[rt<<1|1].r-sum[rt<<1|1].l+1){//理同上
sum[rt].rs+=sum[rt<<1].rs;
}
}
void buildtree(int l,int r,int rt)
{
sum[rt].l=l;
sum[rt].r=r;
sum[rt].ls=sum[rt].rs=sum[rt].ms=r-l+1;
if(l!=r){
int mid=(l+r)>>1;
buildtree(l,mid,rt<<1);
buildtree(mid+1,r,rt<<1|1);
}
}
void update(int rt,int num,int x)
{
if(sum[rt].l==sum[rt].r){
if(x==1){
sum[rt].ls=sum[rt].rs=sum[rt].ms=1;
}
else{
sum[rt].ls=sum[rt].rs=sum[rt].ms=0;
}
return ;
}
int mid=(sum[rt].l+sum[rt].r)>>1;
if(num<=mid){
update(rt<<1,num,x);
}
else{
update(rt<<1|1,num,x);
}
pushup(rt);
}
int query(int rt,int num)
{
if(sum[rt].l==sum[rt].r||sum[rt].ms==0||sum[rt].ms==sum[rt].r-sum[rt].l+1){
return sum[rt].ms;
}
int mid=(sum[rt].r+sum[rt].l)>>1;
if(num<=mid){//在左子树
if(num>=sum[rt<<1].r-sum[rt<<1].rs+1){//如果在左子树的右区间,那么就要再查询右子树的左区间有多长了,也是因为这两个区间是相邻的
return query(rt<<1,num)+query(rt<<1|1,mid+1);
}
else {
return query(rt<<1,num);//没有进入右区间,那只在左子树的查询就好
}
}
else {
if(num<=sum[rt<<1|1].ls+sum[rt<<1|1].l-1){
return query(rt<<1|1,num)+query(rt<<1,mid);
}
else return query(rt<<1|1,num);
}
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF){
char op;
int x;
stack<int> s;
buildtree(1,n,1);
for(int i=1;i<=m;i++)
{
getchar();
scanf("%c",&op);
if(op=='D'){
scanf("%d",&x);
s.push(x);
update(1,x,0);
}
else if(op=='R'){
int k=s.top();
s.pop();
update(1,k,1);
}
else if(op=='Q'){
scanf("%d",&x);
printf("%d\n",query(1,x));
}
}
}
//system("pause");
return 0;
}
POJ3667
//#include <bits/stdc++.h>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <cstring>
using namespace std;
int n,m;
#define maxx 50010
struct node
{
int l,r,ls,rs,ms;//ls是左端最长连续1区间,rs是右端最长连续1区间,ms是l-r区间内最长连续1区间
int lazy;
}sum[maxx<<2];
void pushup(int rt)
{
sum[rt].ls=sum[rt<<1].ls;//首先用子树的ls,rs更新根结点的
sum[rt].rs=sum[rt<<1|1].rs;
sum[rt].ms=max(max(sum[rt<<1].ms,sum[rt<<1|1].ms),sum[rt<<1].rs+sum[rt<<1|1].ls);//利用左右子树的ls,rs,ms求根的ms。
//下面的代码和上面的不能互换位置
if(sum[rt<<1].ls==sum[rt<<1].r-sum[rt<<1].l+1){//如果左子树满了,则要加上右子树的左边区间,因为左右子树管辖的区间是相邻的
sum[rt].ls+=sum[rt<<1|1].ls;//更新这个是为了更新比rt更上层的结点
}
if(sum[rt<<1|1].rs==sum[rt<<1|1].r-sum[rt<<1|1].l+1){//理同上
sum[rt].rs+=sum[rt<<1].rs;
}
}
void pushdown(int rt,int k)
{
if(sum[rt].lazy!=-1)
{
sum[rt<<1].lazy=sum[rt<<1|1].lazy=sum[rt].lazy;
sum[rt<<1|1].ms=sum[rt<<1|1].ls=sum[rt<<1|1].rs=sum[rt].lazy?0:(k>>1);
sum[rt<<1].ms=sum[rt<<1].rs=sum[rt<<1].ls=sum[rt].lazy?0:k-(k>>1);
sum[rt].lazy=-1;
}
}
void buildtree(int l,int r,int rt)
{
sum[rt].l=l;
sum[rt].r=r;
sum[rt].ls=sum[rt].rs=sum[rt].ms=r-l+1;
sum[rt].lazy=-1;
if(l!=r){
int mid=(l+r)>>1;
buildtree(l,mid,rt<<1);
buildtree(mid+1,r,rt<<1|1);
}
}
void update(int rt,int L,int R,int va)
{
if(sum[rt].l>=L&&sum[rt].r<=R)
{
sum[rt].ls=sum[rt].rs=sum[rt].ms=va?0:sum[rt].r-sum[rt].l+1;
sum[rt].lazy=va;
return;
}
pushdown(rt,sum[rt].r-sum[rt].l+1);
int mid=(sum[rt].l+sum[rt].r)>>1;
if(mid>=L) update(rt<<1,L,R,va);
if(mid<R) update(rt<<1|1,L,R,va);
pushup(rt);
}
int query(int rt,int num)
{
if(sum[rt].l==sum[rt].r)
{
return sum[rt].l;
}
pushdown(rt,sum[rt].r-sum[rt].l+1);
int mid=(sum[rt].l+sum[rt].r)>>1;
if(sum[rt<<1].ms>=num)
{
return query(rt<<1,num);
}
else if(sum[rt<<1].rs+sum[rt<<1|1].ls>=num)
{
return mid-sum[rt<<1].rs+1;
}
else return query(rt<<1|1,num);
}
int main()
{
int N,M;
scanf("%d %d",&N,&M);
buildtree(1,N,1);
for(int i=1;i<=M;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
int u;
scanf("%d",&u);
if(sum[1].ms<u)
{
printf("0\n");
}
else
{
int pos=query(1,u);
update(1,pos,pos+u-1,1);
printf("%d\n",pos);
}
}
else
{
int u,v;
scanf("%d %d",&u,&v);
update(1,u,u+v-1,0);
}
}
return 0;
}
维护区间最值
POJ3264
//#include <bits/stdc++.h>
#include <cstdio>
#include <algorithm>
using namespace std ;
#define maxn 50010
int N,Q;
int a[maxn];
struct node
{
int l;
int r;
int v;
int maxV;
int minV;
}sum[maxn<<2];
void pushup(int rt)
{
sum[rt].maxV=max(sum[rt<<1].maxV,sum[rt<<1|1].maxV);
sum[rt].minV=min(sum[rt<<1].minV,sum[rt<<1|1].minV);
}
void buildtree(int rt,int l,int r)
{
sum[rt].l=l;
sum[rt].r=r;
sum[rt].v=0;
sum[rt].maxV=0;
sum[rt].minV=0x3f3f3f3f;
if(l!=r){
int mid=(l+r)>>1;
buildtree(rt<<1,l,mid);
buildtree(rt<<1|1,mid+1,r);
}
}
void update(int rt,int num,int value)
{
if(sum[rt].l==sum[rt].r){
sum[rt].v=value;
sum[rt].maxV=sum[rt].minV=value;
return ;
}
int mid=(sum[rt].l+sum[rt].r)>>1;
if(num<=mid){
update(rt<<1,num,value);
}
else update(rt<<1|1,num,value);
pushup(rt);
}
int querymax(int rt,int L,int R)
{
if(sum[rt].l>=L&&sum[rt].r<=R){
return sum[rt].maxV;
}
if(sum[rt].l==sum[rt].r) return sum[rt].maxV;
int mid=(sum[rt].l+sum[rt].r)>>1;
int maxans=0;
if(mid>=L) {maxans=querymax(rt<<1,L,R);}
if(mid<R) {maxans=max(maxans,querymax(rt<<1|1,L,R));}
return maxans;
}
int querymin(int rt,int L,int R)
{
if(sum[rt].l>=L&&sum[rt].r<=R){
return sum[rt].minV;
}
if(sum[rt].l==sum[rt].r) return sum[rt].minV;
int mid=(sum[rt].r+sum[rt].l)>>1;
int minans=0x3f3f3f3f;
if(mid>=L){
minans=min(minans,querymin(rt<<1,L,R));
}
if(mid<R) {
minans=min(minans,querymin(rt<<1|1,L,R));
}
return minans;
}
int main()
{
scanf("%d %d",&N,&Q);
buildtree(1,1,N);
for(int i=1;i<=N;i++){
scanf("%d",&a[i]);
update(1,i,a[i]);
}
int x,y;
for(int i=1;i<=Q;i++){
scanf("%d %d",&x,&y);
int mx=querymax(1,x,y);
int mi=querymin(1,x,y);
//printf("%d %d\n",mx,mi);
printf("%d\n",mx-mi);
}
//system("pause");
return 0;
}
按树的时间戳建立线段树
题 hdu3974(有区间修改,懒惰标记)
#include <bits/stdc++.h>
using namespace std;
#define maxn 50010
typedef long long ll;
struct node
{
int l,r;
ll task ,lz;
}sum[maxn<<2];
int L[maxn],R[maxn];
vector<int> b[maxn];
int N,M;
int fa[maxn];
int cnt;
void dfs(int u)//通过深搜的时间戳确定每个点的管辖范围
{
L[u]=++cnt;
for(auto &it: b[u]){
dfs(it);
}
R[u]=cnt;
}
void pushdown(int rt)
{
if(sum[rt].lz!=-1){
sum[rt<<1].lz=sum[rt].lz;
sum[rt<<1|1].lz=sum[rt].lz;
sum[rt<<1].task=sum[rt<<1|1].task=sum[rt].task;
sum[rt].lz=-1;
}
}
void buildtree(int rt,int l,int r)
{
sum[rt].l=l;
sum[rt].r=r;
sum[rt].task=-1;
sum[rt].lz=-1;
if(l==r){
return ;
}
else {
int mid=(l+r)>>1;
buildtree(rt<<1,l,mid);
buildtree(rt<<1|1,mid+1,r);
}
}
void update(int rt,ll t,int L,int R)
{
if(sum[rt].l>=L&&sum[rt].r<=R){
sum[rt].task=t;
sum[rt].lz=t;
return ;
}
pushdown(rt);
int mid=(sum[rt].l+sum[rt].r)>>1;
if(mid>=L){
update(rt<<1,t,L,R);
}
if(mid<R){
update(rt<<1|1,t,L,R);
}
}
ll query(int rt,int s)
{
if(sum[rt].l==sum[rt].r){
return sum[rt].task;
}
pushdown(rt);
int mid=(sum[rt].l+sum[rt].r)>>1;
if(mid>=s){
return query(rt<<1,s);
}
else return query(rt<<1|1,s);
}
int main()
{
int T;
scanf("%d",&T);
for(int e=1;e<=T;e++){
scanf("%d",&N);
int u,v;
for(int i=1;i<=N;i++){
fa[i]=i;
b[i].clear();
}
for(int i=1;i<N;i++){
scanf("%d %d",&u,&v);
fa[u]=v;
b[v].push_back(u);
}
cnt=0;
for(int i=1;i<=N;i++){
if(fa[i]==i){
dfs(i);
break;
}
}
buildtree(1,1,N);
scanf("%d",&M);
printf("Case #%d:\n",e);
char op;
int x;
ll y;
for(int i=1;i<=M;i++){
getchar();
scanf("%c",&op);
if(op=='T'){
scanf("%d %lld",&x,&y);
update(1,y,L[x],R[x]);//根据管辖范围插入任务值
}
else {
scanf("%d",&x);
printf("%lld\n",query(1,L[x]));
}
}
}
//system("pause");
return 0;
}