普及向 ZKW線段樹!


啊,是否疲倦了現在的線段樹

太弱,還遞歸!

 

那我們就歡樂的學習另外一種神奇的線段樹吧!(霧

他叫做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));
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM