zoukankan      html  css  js  c++  java
  • 普及向 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("
    ");
    }
    */
    //**************************************************************************************
    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:
    ",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
    ",query(a,b));
            }
        }
    }
  • 相关阅读:
    访问修饰符
    SqlServer 查运行进程
    SqlServer 作业计时执行存储过程,杀超时进程
    VS快捷键操作
    sql server 命令
    vs 加载 dev控件
    TreeList显示[+] [-] 线条样式
    佳能MG2580S清零
    Dev WaitDialog 使用
    导出.txt / .pdf / .xls
  • 原文地址:https://www.cnblogs.com/qscqesze/p/4430454.html
Copyright © 2011-2022 走看看