bzoj3730 (点分树

本文介绍了一种使用点分树的数据结构解决在线查询和单点修改问题,适用于计算距离点x为k的权值和,并能高效地进行权值修改。通过维护两个树状数组分别记录贡献和父节点贡献,结合容斥原理和LCA查询优化,实现了O(nlog2n)的时间复杂度和O(nlogn)的空间复杂度。
摘要由CSDN通过智能技术生成

bzoj3730 (点分树

题意:

1.查询距离x点为k的点的权值和

2.单点修改第x个点的权值

强制在线

思路:

带修且多次询问距离某点

建立点分树维护,每个点开两个树状数组,一个用于维护当前分治区域对自己的贡献,一个维护对父亲的贡献,更新和维护从当前点在点分树上条根即可

注意计算的时候容斥,点分树的老套路了,算上本身后,减去当前对父亲的贡献,算上父亲自己的贡献,注意对于每个分治区域,树状数组的大小,一个是前一个分治子树的大小,一个是自己的分治子树的大小,为了方便,我都开成了上一次的大小,此外,树状数组需要偏移一位防0

点分树常用用RMQ O ( 1 ) O(1) O(1)求LCA(事实上好像没有树剖快?)

时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n) 空间复杂度 O ( n + n / 2 + n / 4... ) = O ( n l o g n ) O(n+n/2+n/4...)=O(nlogn) O(n+n/2+n/4...)=O(nlogn),注意树状数组开vector

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int head[maxn],ver[maxn<<1],next1[maxn<<1],tot,dfn[maxn],d[maxn],st[maxn<<1][21],lg[maxn<<1],ti,sz[maxn],mxson[maxn],rt,S,mxdep,maxdep[maxn],newS;
int n,m,val[maxn],fa[maxn];
bool v[maxn];
void add(int x,int y){
    ver[++tot]=y,next1[tot]=head[x],head[x]=tot;
}
struct BIT{
    #define lowb(x) (x&(-x))
    vector<int>c;
    int N;
    void init(int x){
        N=x-1;
        c.resize(x);
    }
    void add(int x,int val){
        for(int i=x;i<=N;i+=lowb(i))c[i]+=val;
    }
    int ask(int x){
        int ans=0;
        for(int i=x;i;i-=lowb(i))ans+=c[i];
        return ans;
    }
}bit1[maxn],bit2[maxn];
void dfs(int x,int f){
    dfn[x]=++ti;d[x]=d[f]+1;st[ti][0]=x;
    for(int i=head[x];i;i=next1[i]){
        int y=ver[i];
        if(y==f)continue;
        dfs(y,x);
        st[++ti][0]=x;
    }
}
void RMQ(){
    for(int i=2;i<=ti;++i)lg[i]=lg[i>>1]+1;
    for(int j=1;j<=lg[n];++j)
        for(int i=1;(i+(1<<j)-1)<=ti;++i){
            int r=i+(1<<(j-1));
            st[i][j]=d[st[i][j-1]]<d[st[r][j-1]]?st[i][j-1]:st[r][j-1];
        }
}
int query(int l,int r){
    if(l>r)swap(l,r);
    int k=lg[r-l+1];
    return d[st[l][k]]<d[st[r-(1<<k)+1][k]]?st[l][k]:st[r-(1<<k)+1][k];
}
int LCA(int x,int y){
    return query(dfn[x],dfn[y]);
}
void getRoot(int x,int f){
    sz[x]=1;mxson[x]=0;
    newS++;
    for(int i=head[x];i;i=next1[i]){
        int y=ver[i];
        if(y==f||v[y])continue;
        getRoot(y,x);
        sz[x]+=sz[y];
        mxson[x]=max(mxson[x],sz[y]);
    }
    mxson[x]=max(mxson[x],S-mxson[x]);
    if(mxson[x]<mxson[rt])rt=x;
}
void init(int x){
    mxson[rt=0]=maxn;
    S=sz[x];
    getRoot(x,0);
}
void dfz(int x){
    v[x]=1;
    sz[x]=newS+1;//更新之前分治节点的sz用于询问的时候防止越界(或者直接取.size()) 
    bit1[x].init(newS+2);
    bit2[x].init(newS+2);
    for(int i=head[x];i;i=next1[i]){
        int y=ver[i];
        if(v[y])continue;
        newS=0;//用于初始化树状数组 
        init(y);
        fa[rt]=x;
        dfz(rt);
    }
}
int Q(int x,int k,bool flag){
    k=min(k+1,sz[x]);                  //+1因为vector的偏移
    int ans=0;
    ans+=(flag)?bit1[x].ask(k):bit2[x].ask(k);
    return ans;
}
int getDis(int x,int y){
    int lca=LCA(x,y);
    return d[x]+d[y]-2*d[lca];
}
void update(int x,int y){
    for(int i=x;i;i=fa[i])bit1[i].add(getDis(x,i)+1,y);
    for(int i=x;fa[i];i=fa[i])bit2[i].add(getDis(x,fa[i])+1,y);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&val[i]);
    int x,y,op;
    for(int i=1;i<n;++i){
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    dfs(1,0);//预处理LCA
    RMQ();
    mxson[rt=0]=maxn;
    S=n;
    getRoot(1,0);
    fa[rt]=0;
    dfz(rt);
    for(int i=1;i<=n;++i)update(i,val[i]);
    int ans=0;
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&op,&x,&y);
        x^=ans;y^=ans;
        if(!op){
            ans=0;
            ans+=Q(x,y,1);//x子树内距离x<=k的贡献
            for(int f=x;fa[f];f=fa[f]){
                int dd=getDis(x,fa[f]);
                if(y-dd>=0){
                    ans+=Q(fa[f],y-dd,1)-Q(f,y-dd,0);//减去对当前对父亲加上父亲对自己
                }
            }
            cout<<ans<<"\n";
        }else
            update(x,y-val[x]),val[x]=y;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值