線段樹非遞迴實現
程式碼:
#include <iostream> //線段樹。 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; }