线段树递归和非递归实现+hdu1166 敌兵布阵

递归代码:

#include <string>
#include <cstring>
#include <iostream>
#include <stdio.h>
using namespace std;
const int inf=1e5+7;        //最多的数量。
int sum[inf<<2],add[inf<<2];    //其中的值都为零。
int arr[inf],n;

void PushUp(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];}       //应该是按照顺序进行的吧。
void BuiltTree(int l,int r,int rt)      //建树。
{
    if(l==r)        //说明是到达了叶子结点。
    {
        sum[rt]=arr[l];
        return ;
    }
    int m=(l+r)>>1;
    BuiltTree(l,m,rt<<1);
    BuiltTree(m+1,r,rt<<1|1);
    PushUp(rt);
}
//点修改,A[L]+=C;
void UpDate(int l,int r,int L,int C,int rt)
{
    if(l==r)
    {
        sum[rt]+=C;     //这里。
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m)
        UpDate(l,m,L,C,rt<<1);
    else
        UpDate(m+1,r,L,C,rt<<1|1);
    PushUp(rt);
}
//下推标志。
void PushDown(int l,int r,int rt)
{
    if(add[rt])
    {
        int m=(l+r)>>1;
        sum[rt<<1]+=(m-l+1)*add[rt];
        sum[rt<<1|1]+=(r-m)*add[rt];
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        add[rt]=0;

    }
}
//区间修改,A[L到R]+=C;
void UpDate1(int l,int r,int rt,int L,int R,int C)  //有可能有多次修改。所以每到一个结点都要下推标志。
{
    if(l>=L&&r<=R)
    {
        sum[rt]+=(r-l+1)*C;
        add[rt]+=C;
        return ;
    }
    PushDown(l,r,rt);
    int m=(l+r)>>1;
    if(L<=m)
        UpDate1(l,m,rt<<1,L,R,C);
    if(R>m)
        UpDate1(m+1,r,rt<<1|1,L,R,C);
    PushUp(rt);
}
//区间查询。 求arr[L到R]的和。
int DateQuery(int l,int r,int rt,int L,int R)
{
    if(l>=L&&r<=R)
    {
        return sum[rt];
    }
    PushDown(l,r,rt);
    int m=(l+r)>>1;
    int ans=0;      //如果数据过大的话用long long.
    if(L<=m)
        ans+=DateQuery(l,m,rt<<1,L,R);
    if(R>m)
        ans+=DateQuery(m+1,r,rt<<1|1,L,R);
    return ans;
}
void display()
{
    for(int i=1;i<=4*n;i++)
        printf("%d ",sum[i]);
    printf("\n");
}

int main()
{
    cout<<"请输入数组的个数"<<endl;
    cin>>n;
    cout<<"请输入数据"<<endl;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&arr[i]);
    }
    BuiltTree(1,n,1);
    display();
    int flag=0;
    cout<<"是否进行点修改?是,1;否,0"<<endl;
    cin>>flag;
    if(flag==1)
    {
        int C,L;
        cout<<"请输入要修改的点和数据"<<endl;
        cin>>L>>C;
        UpDate(1,n,L,C,1);
        display();
    }
    cout<<"是否进行区间修改,是,1:否,0"<<endl;
    cin>>flag;
    if(flag==1)
    {
        int L,R,C;
        cout<<"请输入左右区间和数据"<<endl;
        cin>>L>>R>>C;
        UpDate1(1,n,1,L,R,C);
        display();
    }
    cout<<"是否进行区间求和,是,1:否,0"<<endl;
    cin>>flag;
    if(flag==1)
    {
        int L,R;
        cout<<"请输入左右端点"<<endl;
        cin>>L>>R;
        cout<<"结果是"<<endl;
        cout<<DateQuery(1,n,1,L,R)<<endl;
    }
    return 0;
}

 

非递归代码:

#include <iostream>           //线段树。 
#include <cstring>
#include <string>
using namespace std;
const int inf=100007;
int Sum[inf<<2];           //初始的应该是零吧。  
int Add[inf<<2];
int A[inf];
int n,N;
void Build(int n)          //首先进行创建。 
{    
	N=1;
	while(N<n+2)N<<=1;  //首先找出N来。     
	for(int i=1;i<=n;i++)            
	Sum[i+N]=A[i];     //之后看看两边的还要管吗。      
	for(int i=N-1;i>0;i--)    
	{        
		Sum[i]=Sum[i<<1]+Sum[i<<1|1];        
		Add[i]=0;          //在这里进行修改吗。       
	}      
}
void Update(int L,int C)           //之后是进行点修改。sum[l]+=C; 
{    
	for(int s=L+N;s;s>>=1)    
	{        
		Sum[s]+=C;    
	}
}
int Query(int L,int R)       //点修改下的区间查询。sum[L R]的和。 
{    
	int ans=0;    
	for(int s=L+N-1,t=R+N+1;s^t^1;s>>=1,t>>=1)    
	{        
		if(~s&1)ans+=Sum[s^1];        
		if(t&1)ans+=Sum[t^1];    
	}    
	return ans;
}
void Update1(int L,int R,int C)   //区间修改Sum[L R]+=C; 
{    
	int s,t,Ln=0,Rn=0,x=1;    
	for(s=L+N-1,t=R+N+1;s^t^1;s>>=1,t>>=1,x<<=1 )    
	{        
		Sum[s]+=Ln*C;        
		Sum[t]+=Ln*C;       //这里。         
		if(~s&1)
			Add[s^1]+=C,Sum[s^1]+=C*x,Ln+=x;         
		if(t&1) 
			Add[t^1]+=C,Sum[t^1]+=C*x,Rn+=x;    
	}    
	for( ;s;s>>=1,t>>=1)    //链接还是巧妙的啊。     
	{        
		Sum[s]+=C*Ln;                
		Sum[t]+=C*Rn;    
	}
}
int Query1(int L,int R)        //区间修改上的区间查询。sum【L,R】的和。 
{    
	int s,t,Ln=0,Rn=0,x=1;    
	int ans=0;    
	for(s=L+N-1,t=R+N+1;s^t^1;s>>=1,t>>=1,x<<=1)    
	{        
		if(Add[s])ans+=Add[s]*Ln;        
		if(Add[t])ans+=Add[t]*Rn;         
		if(~s&1)ans+=Sum[s^1],Ln+=x;        
		if( t&1)ans+=Sum[t^1],Rn+=x;    
	}    
	for( ;s;s>>=1,t>>=1)                    //其实加不加是无所谓的。              
	{        
		/*if( Add[s])*/
		ans+=Add[s]*Ln;        //这里为何是不加的呢。              
		/*if( Add[t])*/
		ans+=Add[t]*Rn;                            
	}    
	return ans;                                 
}

int main()
{   
	cout<<"请输入数组的个数"<<endl;     
	cin>>n;     
	cout<<"请输入数组中的值"<<endl;     
	for(int i=1;i<=n;i++)         
		cin>>A[i];     
	Build(n);   //初始化。      
	for(int i=1;i<=2*N-1;i++)              
	cout<<Sum[i]<<" ";        
	cout<<endl;    
	Update(3,1);    
	for(int i=1;i<=2*N-1;i++)        
		cout<<Sum[i]<<" ";        
	cout<<endl;    
	int ans=Query(2,4);        
	cout<<ans<<endl;    
	Update1(2,4,1);    
	for(int i=1;i<=2*N-1;i++)        
		cout<<Sum[i]<<" ";        
	cout<<endl;    
	int ans1=Query1(1,4);                //最后一个。              
	cout<<ans1<<endl;  
	return 0; 
} 

hdu1166 敌兵布阵

http://acm.hdu.edu.cn/showproblem.php?pid=1166

简单线段树点修改和区间查询:

代码:

#include <string>
#include <cstring>
#include <iostream>
#include <stdio.h>
using namespace std;
const int inf=1e5+7;        //最多的数量。
int sum[inf<<2],add[inf<<2];    //其中的值都为零。
int arr[inf],n;

void PushUp(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];}       //应该是按照顺序进行的吧。
void BuiltTree(int l,int r,int rt)      //建树。
{
    if(l==r)        //说明是到达了叶子结点。
    {
        sum[rt]=arr[l];
        return ;
    }
    int m=(l+r)>>1;
    BuiltTree(l,m,rt<<1);
    BuiltTree(m+1,r,rt<<1|1);
    PushUp(rt);
}
//点修改,A[L]+=C;
void UpDate(int l,int r,int L,int C,int rt)
{
    if(l==r)
    {
        sum[rt]+=C;     //这里。
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m)
        UpDate(l,m,L,C,rt<<1);
    else
        UpDate(m+1,r,L,C,rt<<1|1);
    PushUp(rt);
}
//下推标志。
void PushDown(int l,int r,int rt)
{
    if(add[rt])
    {
        int m=(l+r)>>1;
        sum[rt<<1]+=(m-l+1)*add[rt];
        sum[rt<<1|1]+=(r-m)*add[rt];
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        add[rt]=0;

    }
}
//区间修改,A[L到R]+=C;
void UpDate1(int l,int r,int rt,int L,int R,int C)  //有可能有多次修改。所以每到一个结点都要下推标志。
{
    if(l>=L&&r<=R)
    {
        sum[rt]+=(r-l+1)*C;
        add[rt]+=C;
        return ;
    }
    PushDown(l,r,rt);
    int m=(l+r)>>1;
    if(L<=m)
        UpDate1(l,m,rt<<1,L,R,C);
    if(R>m)
        UpDate1(m+1,r,rt<<1|1,L,R,C);
    PushUp(rt);
}
//区间查询。 求arr[L到R]的和。
int DateQuery(int l,int r,int rt,int L,int R)
{
    if(l>=L&&r<=R)
    {
        return sum[rt];
    }
    PushDown(l,r,rt);
    int m=(l+r)>>1;
    int ans=0;      //如果数据过大的话用long long.
    if(L<=m)
        ans+=DateQuery(l,m,rt<<1,L,R);
    if(R>m)
        ans+=DateQuery(m+1,r,rt<<1|1,L,R);
    return ans;
}
void display()
{
    for(int i=1;i<=4*n;i++)
        printf("%d ",sum[i]);
    printf("\n");
}

int main()
{
    int t;
	scanf("%d",&t);
	int abc=1;
	while(t--)
	{
		printf("Case %d:\n",abc++);
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%d",&arr[i]);
		BuiltTree(1,n,1);
		string str;
		while(1)
		{
			cin>>str;
			if(str=="End")
				break;
			int a,b;
			scanf("%d %d",&a,&b);
			if(str=="Query")
			{
				printf("%d\n",DateQuery(1,n,1,a,b));
			}	
			else if(str=="Add")
				UpDate(1,n,a,b,1);
			else
			{
				b=-1*b;
				UpDate(1,n,a,b,1);
			}	
		}
	}
    return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值