香香的鸽子
发布于 2025-06-23 / 1 阅读
0
0

zkw主席树实现单修区查

由于zkw线段树的特征,其实现主席树时不能自底向上做区间查询,也许记录父节点也可以?我没有再考虑。

不过可以麻烦一点自上而下做。

今天上午对着P10814 【模板】离线二维数点导管的时候想用zkw实现主席树在线做一下,后来发现 2e6 其实已经把空间卡爆了()

总之我研究了一种从上往下做区间查询的写法,比较丑陋,不过好在是对的,并且这种做法对于zkw线段树的其他形式也能用(就是把从下往上查的做法颠倒了下顺序,有些时候完全没必要)

爆炒 lxl 失败了,但还是纪念一下...

放个代码:

点击查看代码
#include<bits/stdc++.h>
//#define int long long
#define ll long long
#define db double
#define ili inline
#define fir first
#define sec second
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#define pb push_back
template <typename T>
ili void rd(T &x){
    int f=1;x=0;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    x*=f;
}
template <typename T,typename...Args>
ili void rd(T&x,Args&...args){
    rd(x),rd(args...);
}
template <typename T>
ili void wr(T x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else wr<T>(x/10),putchar(x%10+'0');
}
using namespace std;
const int N=1e6+1e6;
const int LG=20;
int n,m,a[N];
int son[N*3+N*LG][2],rt[N],t[N*3+N*LG];
int P=1,DEP,OST;s
ili void add(int i,int ver,int l,int k){
    int tl=l+P;
    int v=rt[ver];
    rt[i]=l=++OST;
    t[l]=t[v]+k;
    for(int dep=DEP-1;dep>=0;dep--){
        if((tl>>dep)&1) son[l][0]=son[v][0],son[l][1]=++OST,v=son[v][1];
        else son[l][1]=son[v][1],son[l][0]=++OST,v=son[v][0];
        l=OST,t[l]=t[v]+k;
    }
}
ili int query(int ver,int x){
    int tl=1+P-1,tr=x+P+1;
    //左链右链指向的节点
    int nowl,nowr;
    nowl=nowr=rt[ver];
    int res=0;
    for(int dep=DEP-1;dep>=0;dep--){
        //当前指向的原树左右节点
        int nl=(tl>>dep),nr=(tr>>dep);
        //相等即两条链的公共祖先,不需要计算,往下指
        if(nl==nr){
            if(~nl&1) nowl=nowr=son[nowl][0];
            else nowl=nowr=son[nowl][1];
        }
        //互为兄弟,不需要计算,但需要更新指向这一层
        else if((nl^1^nr)==0){
            nowl=son[nowl][0];
            nowr=son[nowr][1];
        }
        //这层可能计算,具体看原树节点是否满足选取标准
        else{
            //左链为左子树,选右子树,选完指向左边
            if(~nl&1) res=res+t[son[nowl][1]],nowl=son[nowl][0];
            //否则指向右边继续选取
            else nowl=son[nowl][1];
            //右链为右子树,选左子树
            if(nr&1) res=res+t[son[nowr][0]],nowr=son[nowr][1];
            else nowr=son[nowr][0];
        }
    }
    return res;
}
void xpigeon(){
    rd(n,m);
    while(P<=n+1) P<<=1,++DEP;
    OST=(P<<1)-1;
    for(int i=1;i<=n;i++){
        rd(a[i]);
    }
    rt[0]=1;
    for(int i=P-1;i;i--) son[i][0]=i<<1,son[i][1]=i<<1|1;
    for(int i=1;i<=n;i++){
        add(i,i-1,a[i],1);
    }
    for(int i=1,l,r,x;i<=m;i++){
        rd(l,r,x);
        int ans=query(r,x)-query(l-1,x);
        cout<<ans<<'\n';
    }
}  
signed main(){
    // ios::sync_with_stdio(false);
    // cin.tie(NULL);
    // cout.tie(NULL);
    xpigeon();
    return 0;
}

评论