QOJ 5020. 举办乘凉州喵,举办乘凉州谢谢喵

QOJ 5020. 举办乘凉州喵,举办乘凉州谢谢喵

飞天数据结构。

思路

f[u][k]u 子树内距离 u 小于等于 k 的点的个数,g[u][k]u 的轻子树中距离小于等于 k 的点的个数。

对于一条路径 (x,y) 来说,设其 Lcaz 我们不妨看成是一条 xz 和一条 yz 的路径。

这种祖先关系的路径,如果是一条重链上那么答案是 u(xz)g[u][k]+f[hsou][k1]f[z][k]+|xz|hsouu 的重儿子)加上距离 zk 以内的点的个数。

如果是若干条重链拼在一起,先加上链上的 g[u][k],对于一条轻边 (u,v),设父亲是 v,那么需要减 f[u][k]f[hsov][k1]

跳重链,把所有 f,g 值离线到点。

对于 f 值,可以视作一个二维偏序,不过这样就 qlog3n 了。更好的方法是使用树状树组存深度个数,遍历到该点时查询一次深度不大于 k 的个数,与遍历出该点时深度不大于 k 的个数作差。

对于 g 值,每到一个点暴力的跑轻子树,将轻子树与其的距离加入树状树组 G,此时 Gkgu,k,不清空遍历儿子,这样就是根到当前节点的 g 的和,类似树上查询深度的方式即可解决 g 的查询。

对于求一个点距离不超过 k 的点的个数,是点分治的经典问题。

CODE

#include<bits/stdc++.h>
using namespace std;

#define N 200000

const int maxn=2e5+5;

int q,n;
int ans[maxn];

struct treearray
{
    int ts[maxn];
    inline int lowbit(int x){return x&(-x);}
    inline void updata(int x,int y){for(;x<=N;x+=lowbit(x)) ts[x]+=y;}
    inline int getsum(int x){int sum=0;for(;x;x-=lowbit(x)) sum+=ts[x];return sum;}
}Sdep,G,Sdis,Tdis;
struct Edge
{
    int tot;
    int head[maxn];
    struct edgenode{int to,nxt;}edge[maxn*2];
    inline void add(int x,int y)
    {
        tot++;
        edge[tot].to=y;
        edge[tot].nxt=head[x];
        head[x]=tot;
    }
}T;
struct QRY{int fx,d,id;};
struct QRY_f{int fx,l,r,id;};

int hso[maxn],dep[maxn],fa[maxn],siz[maxn],tp[maxn];

vector<QRY>gvec[maxn],dvec[maxn];
vector<QRY_f>fvec[maxn];

inline void dfs(int u,int f)
{
    dep[u]=dep[f]+1;fa[u]=f;siz[u]=1;
    for(int i=T.head[u];i;i=T.edge[i].nxt)
    {
        int v=T.edge[i].to;
        if(v==f) continue;
        dfs(v,u);
        siz[u]+=siz[v];
        if(siz[v]>siz[hso[u]]) hso[u]=v;
    }
}
inline void dfs2(int u,int t)
{
    tp[u]=t;
    if(hso[u]) dfs2(hso[u],t);
    for(int i=T.head[u];i;i=T.edge[i].nxt)
    {
        int v=T.edge[i].to;
        if(v==fa[u]||v==hso[u]) continue;
        dfs2(v,v);
    }
}
inline int Lca(int u,int v)
{
    while(tp[u]!=tp[v])
    {
        if(dep[tp[u]]<dep[tp[v]]) swap(u,v);
        u=fa[tp[u]];
    }
    if(dep[u]<dep[v]) swap(u,v);
    return v;
}

namespace solvefg
{
    inline void dfsf(int u,int f)
    {
        for(auto v:fvec[u])
            ans[v.id]-=(Sdep.getsum(v.r)-Sdep.getsum(v.l-1))*v.fx;
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(v==f) continue;
            dfsf(v,u);
        }
        Sdep.updata(dep[u],1);
        for(auto v:fvec[u])
            ans[v.id]+=(Sdep.getsum(v.r)-Sdep.getsum(v.l-1))*v.fx;
    }
    inline void dfs_cnt(int u,int f,int dis,int val)
    {
        G.updata(dis,val);
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(v==f) continue;
            dfs_cnt(v,u,dis+1,val);
        }
    }
    inline void dfsg(int u,int f)
    {
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(v==f||v==hso[u]) continue;
            dfs_cnt(v,u,1,1);
        }
        for(auto v:gvec[u]) ans[v.id]+=G.getsum(v.d)*v.fx;
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(v==f) continue;
            dfsg(v,u);
        }
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(v==f||v==hso[u]) continue;
            dfs_cnt(v,u,1,-1);
        }
    }
    inline void goup(int u,int v,int d,int id)
    {
        ans[id]+=dep[u]-dep[v]+1;
        gvec[u].push_back({1,d,id});gvec[fa[v]].push_back({-1,d,id});
        fvec[hso[u]].push_back({1,dep[u],min(dep[u]+d,n),id});
        while(tp[u]!=tp[v])
        {
            u=tp[u];
            fvec[u].push_back({-1,dep[fa[u]],min(dep[fa[u]]+d,n),id});
            u=fa[u];
            fvec[hso[u]].push_back({1,dep[u],min(dep[u]+d,n),id});
        }
    }
}
namespace treediv
{
    int siz[maxn];
    bool book[maxn],cut[maxn];
    inline void dfs_siz(int u)
    {
        book[u]=true;siz[u]=1;
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(book[v]||cut[v]) continue;
            dfs_siz(v);siz[u]+=siz[v];
        }
        book[u]=false;
    }
    inline int dfs_rt(int u,const int tot)
    {
        book[u]=true;int ret=u;
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(book[v]||cut[v]) continue;
            if(siz[v]*2>=tot) {ret=dfs_rt(v,tot);break;}
        }
        book[u]=false;return ret;
    }
    inline void dfs_cnt(int u,int dis,int val)
    {
        Sdis.updata(dis+1,val);
        book[u]=true;
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(book[v]||cut[v]) continue;
            dfs_cnt(v,dis+1,val);
        }
        book[u]=false;
    }
    inline void dfs_ept(int u,int dis,int val)
    {
        Tdis.updata(dis+1,val);
        book[u]=true;
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(book[v]||cut[v]) continue;
            dfs_ept(v,dis+1,val);
        }
        book[u]=false;
    }
    inline void calc(int u,int dis)
    {
        for(auto i:dvec[u])
        {
            if(i.d-dis+1<0) continue;
            ans[i.id]+=Sdis.getsum(i.d-dis+1)-Tdis.getsum(i.d-dis+1);
        }
    }
    inline void dfs_calc(int u,int dis)
    {
        book[u]=true;calc(u,dis);
        for(int i=T.head[u];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(book[v]||cut[v]) continue;
            dfs_calc(v,dis+1);
        }
        book[u]=false;
    }
    inline void dfs(int u)
    {
        dfs_siz(u);int g=dfs_rt(u,siz[u]);cut[g]=true;
        dfs_cnt(g,0,1);
        calc(g,0);
        for(int i=T.head[g];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(cut[v]) continue;
            dfs_ept(v,1,1);
            dfs_calc(v,1);
            dfs_ept(v,1,-1);
        }
        dfs_cnt(g,0,-1);
        for(int i=T.head[g];i;i=T.edge[i].nxt)
        {
            int v=T.edge[i].to;
            if(cut[v]) continue;
            dfs(v);
        }
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        T.add(u,v),T.add(v,u);
    }
    dfs(1,0),dfs2(1,1);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        int u,v,d;
        scanf("%d%d%d",&u,&v,&d);
        int lca=Lca(u,v);
        fvec[lca].push_back({-2,dep[lca],min(dep[lca]+d,n),i});
        dvec[lca].push_back({1,d,i});
        solvefg::goup(u,lca,d,i);solvefg::goup(v,lca,d,i);
    }
    solvefg::dfsf(1,0);
    solvefg::dfsg(1,0);
    treediv::dfs(1);
    for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
}
posted @   彬彬冰激凌  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示