啊,是否疲倦了現在的線段樹
太弱,還遞歸!
那我們就歡樂的學習另外一種神奇的線段樹吧!(霧
他叫做zkw線段樹
這個數據結構灰常好寫(雖然線段樹本身也特別好寫……)
速度快(貌似只在單點更新方面比線段樹快……)
是一種自底向上非遞歸版本的線段樹!
首先我們來看一個ppt,《統計的力量》這個是發明人的PPT(啊,ppt內的代碼是錯的……
好吧,我們來寫吧~
首先預備條件:
int M,T[maxn*2+2];
M指的是什么呢?M就指的是這顆zkw線段樹最下面的那個點之前的編號是什么
T數組就是這個zkw線段樹的數組,由於zkw線段樹是一顆滿二叉樹,所以直接開兩倍就好啦~
接下來我們就來建樹吧!
以單點更新,區間查詢和作為一個例子~
void build(int x) { for(M=1;M<=n+1;M<<1); for(int i=1;i<=n;i++) scanf("%d",&T[i+M]); for(int i=M-1;i;i--) T[i]=T[i<<1]+T[i<<1|1]; }
很顯然這是一顆非常弱的從底往上更新的樹!
然后updata怎么寫呢?qsc仔細想了想,很簡單
void updata(int n,int val) { T[n+=M]=val;//這個地方是單點修改的喲 for(n>>=1;n;n>>=1) T[n]=T[n<<1]+T[n<<1|1]; }
哇,其實和線段樹是一個意思,直接順着節點直接往上爬就是了!
query腫么寫呢?還是很簡單呀
int query(int l,int r) { int ans=0; l=l+M-1,r=r+M+1; for(;l^r^1;l>>1,r>>=1) { if(~l&1)ans+=T[l^1]; if(r&1) ans+=T[r^1]; } return ans; }
這個亂七八糟的位運算什么意思呀?
l^r^1的意思,就是左邊的這個點和右邊這個點是否互為兄弟,或者干脆就是一個點
~l&1 就是判斷這個左邊這個是否為左兒子,r&1判斷這個節點是否為右二子
如果是的話,那就得加上他的兄弟咯~
啊,zkw單點更新區間查詢就示范到這兒了,是不是灰常簡單呀~
我們首先來搞一道例題:
HDU 1166 敵兵布陣 單點更新,區間查詢
//qscqesze #include <cstdio> #include <cmath> #include <cstring> #include <ctime> #include <iostream> #include <algorithm> #include <set> #include <vector> #include <sstream> #include <queue> #include <typeinfo> #include <fstream> #include <map> #include <stack> typedef long long ll; using namespace std; //freopen("D.in","r",stdin); //freopen("D.out","w",stdout); #define sspeed ios_base::sync_with_stdio(0);cin.tie(0) #define maxn 200001 #define mod 10007 #define eps 1e-9 //const int inf=0x7fffffff; //無限大 const int inf=0x3f3f3f3f; /* int buf[10]; inline void write(int i) { int p = 0;if(i == 0) p++; else while(i) {buf[p++] = i % 10;i /= 10;} for(int j = p-1; j >=0; j--) putchar('0' + buf[j]); printf("\n"); } */ //************************************************************************************** inline ll read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } ll T[maxn*4]; int M,n; void build() { for(M=1;M<=n+1;M<<=1); for(int i=1;i<=n;i++) T[i+M]=read(); for(int i=M-1;i;i--) T[i]=T[i<<1]+T[i<<1|1]; } void updata(int x,int val) { T[x+=M]+=val; for(x>>=1;x>=1;x>>=1) { T[x]=T[x<<1]+T[x<<1|1]; } } ll query(int l,int r) { l=l+M-1,r=r+M+1; ll ans=0; for(;l^r^1;l>>=1,r>>=1) { if(~l&1)ans+=T[l^1]; if(r&1) ans+=T[r^1]; } return ans; } int main() { int cas=0; int t=read(); string s; for(int cas=1;cas<=t;cas++) { memset(T,0,sizeof(T)); printf("Case %d:\n",cas); n=read(); build(); while(cin>>s) { if(s[0]=='E') break; int a,b; a=read(),b=read(); if(s[0]=='A') updata(a,b); else if(s[0]=='S') updata(a,-b); else printf("%lld\n",query(a,b)); } } }