递归代码:
#include
#include
#include
#include
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<<"请输入数组的个数"<>n;
cout<<"请输入数据"<>flag;
if(flag==1)
{
int C,L;
cout<<"请输入要修改的点和数据"<>L>>C;
UpDate(1,n,L,C,1);
display();
}
cout<<"是否进行区间修改,是,1:否,0"<>flag;
if(flag==1)
{
int L,R,C;
cout<<"请输入左右区间和数据"<>L>>R>>C;
UpDate1(1,n,1,L,R,C);
display();
}
cout<<"是否进行区间求和,是,1:否,0"<>flag;
if(flag==1)
{
int L,R;
cout<<"请输入左右端点"<>L>>R;
cout<<"结果是"<
非递归代码:
#include //线段树。
#include
#include
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(N0;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<<"请输入数组的个数"<>n;
cout<<"请输入数组中的值"<>A[i];
Build(n); //初始化。
for(int i=1;i<=2*N-1;i++)
cout<
hdu1166 敌兵布阵
http://acm.hdu.edu.cn/showproblem.php?pid=1166
简单线段树点修改和区间查询:
代码:
#include
#include
#include
#include
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;
}