bzoj3730: 震波(点分树+bit)

传送门
点分树板题。。。
然而并没有遇到卡常之类的事。。。
对于分出来的每一层用两棵 B i t Bit 动态维护到自己距离不超过 k k 的与到自己点分树父亲距离不超过 k k 的点数。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
    static char buf[rlen],*ib,*ob;
    (ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
    return ib==ob?-1:*ib++;
}
inline int read(){
    int ans=0;
    char ch=gc();
    while(!isdigit(ch))ch=gc();
    while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
    return ans;
}
const int N=1e5+5;
vector<int>e[N];
int n,m,a[N];
struct Bit{
    int up;
    vector<int>bit;
    inline int lowbit(const int&x){return x&-x;}
    inline void init(const int&k){bit.resize(k+10),up=k+8;}
    inline void update(int x,const int&v){++x;for(ri i=x;i<=up;i+=lowbit(i))bit[i]+=v;}
    inline int query(int x){int ret=0;++x;for(ri i=min(x,up);i>0;i^=lowbit(i))ret+=bit[i];return ret;}
}t1[N],t2[N];
int siz[N],hson[N],top[N],fa[N],dep[N],all,ms,rt,Fa[N];
bool vis[N];
void dfs1(int p){
    siz[p]=1;
    for(ri i=0,v;i<e[p].size();++i){
        if((v=e[p][i])==fa[p])continue;
        fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
        if(siz[v]>siz[hson[p]])hson[p]=v;
    }
}
void dfs2(int p,int tp){
    top[p]=tp;
    if(!hson[p])return;
    dfs2(hson[p],tp);
    for(ri i=0,v;i<e[p].size();++i)if((v=e[p][i])!=fa[p]&&v!=hson[p])dfs2(v,v);
}
inline int lca(int x,int y){
    int ret=dep[x]+dep[y];
    while(top[x]^top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return ret-2*dep[dep[x]<dep[y]?x:y];
}
void getroot(int p,int fa){
    siz[p]=1;
    int mss=0;
    for(ri i=0,v;i<e[p].size();++i){
        if((v=e[p][i])==fa||vis[v])continue;
        getroot(v,p),siz[p]+=siz[v],mss=max(mss,siz[v]);
    }
    mss=max(mss,all-siz[p]);
    if(mss<ms)ms=mss,rt=p;
}
int mdp=0,mdpp=0;
void dfs(int p,int fa,int dist,int anc){
    siz[p]=1,mdp=max(mdp,dist);
    if(anc)mdpp=max(mdpp,lca(anc,p));
    for(ri i=0,v;i<e[p].size();++i){
        if(vis[v=e[p][i]]||v==fa)continue;
        dfs(v,p,dist+1,anc),siz[p]+=siz[v];
    }
}
inline void solve(int p){
    vis[p]=1,mdp=1,mdpp=1,dfs(p,0,0,Fa[p]);
    t1[p].init(mdp);
    if(Fa[p])t2[p].init(mdpp);
    for(ri i=0,v;i<e[p].size();++i){
        if(vis[v=e[p][i]])continue;
        all=ms=siz[v],getroot(v,0),Fa[rt]=p,solve(rt);
    }
}
inline int query(int x,int k){
    int ret=0;
    for(ri t,i=x;i;i=Fa[i]){
        if((t=lca(x,i))>k)continue;
        ret+=t1[i].query(k-t);
    }
    for(ri t,i=x;Fa[i];i=Fa[i]){
        if((t=lca(x,Fa[i]))>k)continue;
        ret-=t2[i].query(k-t);
    }
    return ret;
}
inline void update(int x,int v){
    for(ri i=x;i;i=Fa[i]){
        t1[i].update(lca(x,i),v-a[x]);
        if(Fa[i])t2[i].update(lca(x,Fa[i]),v-a[x]);
    }
    a[x]=v;
}
int main(){
    n=read(),m=read();
    for(ri i=1;i<=n;++i)a[i]=read();
    for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    dfs1(1),dfs2(1,1);
    all=ms=n,getroot(1,0),solve(rt);
    for(ri i=1;i<=n;++i){
        for(ri j=i;j;j=Fa[j]){
            t1[j].update(lca(i,j),a[i]);
            if(Fa[j])t2[j].update(lca(i,Fa[j]),a[i]);
        }
    }
    for(ri ans=0,op,x,y;m;--m){
        op=read(),x=read()^ans,y=read()^ans;
        switch(op){
            case 0:{
                cout<<(ans=query(x,y))<<'\n';
                break;
            }
            case 1:{
                update(x,y);
                break;
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/93754570
今日推荐