线段树学习

学习链接

带有down的线段树模板

数组开的是2*n

左孩纸是 n+1

右孩纸是n+(左孩子区间长度+1)*2

线段树题目 

I Hate It    HDU - 1754 

敌兵布阵  HDU - 1166

Color the ball  HDU - 1556 

#include<iostream>
#define max 100
using namespace std;
struct node {
	int left ,right,w,f;  //f是懒标记 
};
node tree[max*2+10];
void bulid(int l,int r,int k){
	tree[k].left=l;
	tree[k].right=r;
	if(l==r){
		cin>>tree[k].w;		
		return ;
	}
	int mid=(l+r)/2;
	bulid(l,mid,k+1);
	bulid(mid+1,r,k+(mid-l+1)*2);
	tree[k].w=tree[k+1].w+tree[k+(mid-l+1)*2].w;
}
int ask(int k,int index){  //单点查询 返回第k个元素的值  
	if(tree[index].left==tree[index].right){
		return tree[index].w;
	}
	int mid=(tree[index].left+tree[index].right)/2;
	if(mid>=k)
		ask(k,index+1);
	else 
		ask(k,index+((mid-tree[index].left)+1)*2);
}
void add(int k,int index,int add_){  //单点修改 修改第k个元素的值 
	tree[index].w+=add_;
	if(tree[index].left==tree[index].right){
		return;
	}
	int mid=(tree[index].left+tree[index].right)/2;
	if(mid>=k){
		add(k,index+1,add_);
	}
	else {
		add(k,index+((mid-tree[index].left)+1)*2,add_);
	}
}
void down(int index){   ///tree[index].f 指的是未更新子节点,自己本身已经更新了 
	tree[index+1].f+=tree[index].f;
	int index_right=((tree[index].left+tree[index].right)/2-tree[index].left+1)*2;
	tree[index_right].f+=tree[index].f;
	tree[index+1].w+=tree[index].f*(tree[index+1].right-tree[index+1].left+1);
	tree[index_right].w+=tree[index].f*(tree[index_right].right-tree[index_right].left+1);
	tree[index].f=0;
}
int request(int ll,int rr,int index){
	int left=tree[index].left;
	int right=tree[index].right;
	if(left==ll&&right==rr){
		return tree[index].w;
	}
	int mid=(left+right)/2;
	if(mid>=rr){  //【ll,rr】区间是【left,mid】 的子区间 
		if(tree[index].f)
			down(index);
		return request(ll,rr,index+1);
	}
	else if(mid<ll){  //【ll,rr】区间是【mid,right】的子区间 
		if(tree[index].f)
			down(index);
		return request(ll,rr,index+(mid-left+1)*2);
	} 
	else {  //【ll,rr】 区间包括了mid    
		if(tree[index].f)
			down(index);
		return request(ll,mid,index+1)+request(mid+1,rr,index+(mid-left+1)*2);
	}
}
void add_interval(int ll,int rr,int index,int num){//num是给区间【ll,rr】 中每个点加的数 
	cout<<ll<<"  "<<rr<<"  "<<index <<"  "<<num<<endl; 
	int left=tree[index].left;
	int right=tree[index].right;
	if(left==ll&&right==rr){
		tree[index].w+=(right-left+1)*num; 
		tree[index].f=num; 
		return ;
	}
	int mid=(left+right)/2;
	if(mid>=rr){  //【ll,rr】区间是【left,mid】 的子区间 
		add_interval(ll,rr,index+1,num);
	}
	else if(mid<ll){  //【ll,rr】区间是【mid,right】的子区间 
		add_interval(ll,rr,index+(mid-left+1)*2,num);
	} 
	else {  //【ll,rr】 区间包括了mid    
		add_interval(ll,mid,index+1,num);
		add_interval(mid+1,rr,index+(mid-left+1)*2,num);
	}
}
int main(){
	int n,m;
	cin>>n;
	bulid(1,n,1);
	for(int i=1;i<=9;i++)
		cout<<i<<"   "<<tree[i].left<<"  "<<tree[i].right<<"  "<<tree[i].w<<endl;
	add(1,1,1);
	for(int i=1;i<=9;i++)
		cout<<i<<"   "<<tree[i].left<<"  "<<tree[i].right<<"  "<<tree[i].w<<endl;
	return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值