1 条题解

  • 0
    @ 2025-8-24 23:05:36

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 是青白呀
    咕咕咕?咕咕咕!

    搬运于2025-08-24 23:05:36,当前版本为作者最后更新于2025-01-08 20:59:24,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    考虑一个建图方式:建立 nn 个点表示病毒的中转点,对每个人的点 ii,找到所有距离 pip_i 小于等于 did_i 的树上点,它们的中转点向 ii00 的边,ii 向它们的中转点连 cic_i 的边。直接跑 dij 可以做到 O(n2logn)O(n^2\log n)

    考虑优化“ii 这个人向所有距离它小于等于 did_i 的中转点连权值为 vv 的正向或反向边”。考虑点分治优化,一个深度为 depidep_i 的点能向所有深度小于等于 didepid_i-dep_i 的点连边。下面以正向为例:考虑建立 dep+1dep+1 个虚点,每个虚点向该深度下的实际中转点连 vv 的边;虚点之间由深度 xx1x\to x-100 边;考察每个人对应的点,向 didepid_i-dep_i 对应的虚点连 00 边。反向边只需要将上述所有边反向,且去掉虚点连出来的边的权值即可。

    这样,点分治过程中每个连通块的点、边数为 O(size)O(size),总数为 O(nlogn)O(n\log n) 级别。直接跑 dij 可以做到 O(nlog2n)O(n\log^2 n),已经可以通过了。

    还有一些优化。对于每个中转点,我们再拆成入点和出点,这样只有 O(n)O(n) 条出入点之间的边有权值。在 dij 的过程中,我们借用 01BFS 的思想,对于有权值的边,我们扔进优先队列;对于 00 权边,我们使用普通队列,直接维护。每次弹出时,优先弹出普通堆的点即可。这样只有 O(n)O(n) 条边会进堆,复杂度做到 O(nlogn)O(n\log n)。似乎优化效果不明显。

    #include<bits/stdc++.h>
    #define rep(i,j,k) for(int i=j;i<=k;i++)
    #define repp(i,j,k) for(int i=j;i>=k;i--)
    #define pii pair<int,int>
    #define mp make_pair
    #define fir first
    #define sec second
    #define ls(x) (x<<1)
    #define rs(x) ((x<<1)|1)
    #define lowbit(i) (i&-i)
    #define qingbai qwq
    using namespace std;
    typedef long long ll;
    const int N=1e5+5,M=2e6+5,mo=1e9+7;
    const ll inf=(ll)1e18+7;
    void read(int &a){
        int x=0,w=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')w=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            x=(x<<3)+(x<<1)+ch-'0';
            ch=getchar();
        }
        a=x*w;
    }
    int n,m,p[N],d[N],c[N];
    vector<int>et[N];
    int cntp,id[N];
    vector<int>perc[N];
    int maxs[N],sz[N],rt,tot;
    bool vis[N];
    void dfs1(int x,int f){
        maxs[x]=0,sz[x]=1;
        for(auto j:et[x]){
            if(vis[j]||j==f)continue;
            dfs1(j,x),sz[x]+=sz[j],maxs[x]=max(maxs[x],sz[j]);
        }
        maxs[x]=max(maxs[x],tot-sz[x]);
        if(maxs[x]<maxs[rt])rt=x;
    }
    vector<pii>e[N*45];
    int dep[N],idd[N],maxd=0;
    void dfs2(int x,int f){
        dep[x]=dep[f]+1,maxd=max(maxd,dep[x]);
        for(auto j:et[x]){
            if(j==f||vis[j])continue;
            dfs2(j,x);
        }
    }
    void dfs3(int x,int f){
        for(auto j:et[x])
            if(j!=f&&!vis[j])dfs3(j,x);
        for(auto j:perc[x]){
            int topos=min(maxd,d[j]-dep[x]);
            if(topos<0)continue;
            e[id[j]].push_back(mp(idd[topos],0));
            e[idd[topos]+1].push_back(mp(id[j],0));
        }
        e[idd[dep[x]]].push_back(mp(x,0));
        e[x+n].push_back(mp(idd[dep[x]]+1,0));
    }
    void dfz(int x){
        maxd=0,dep[0]=-1,dfs2(x,0);
        rep(i,0,maxd)
            idd[i]=++cntp,cntp++;
        rep(i,1,maxd){
            e[idd[i]].push_back(mp(idd[i-1],0));
            e[idd[i-1]+1].push_back(mp(idd[i]+1,0));
        }
        dfs3(x,0);
        vis[x]=1;
        for(auto j:et[x]){
            if(vis[j])continue;
            rt=0,tot=sz[j],dfs1(j,x),dfz(rt);
        }
    }
    ll dis[N*45];
    bool visd[N*45];
    void dij(){
        queue<pair<ll,int>>q;
        priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>>pq;
        rep(i,1,cntp)
            dis[i]=inf,visd[i]=0;
        dis[id[1]]=0,pq.push(mp(0ll,id[1]));
        while(!q.empty()||!pq.empty()){
            int x;ll v;
            if(!q.empty())tie(v,x)=q.front(),q.pop();
            else tie(v,x)=pq.top(),pq.pop();
            if(visd[x])continue;
            visd[x]=1;
            for(auto j:e[x]){
                if(visd[j.fir]||dis[j.fir]<=dis[x]+j.sec)continue;
                dis[j.fir]=dis[x]+j.sec;
                if(!j.sec)q.push(mp(dis[j.fir],j.fir));
                else pq.push(mp(dis[j.fir],j.fir));
            }
        }
    }
    vector<ll>ans;
    vector<long long> find_spread(int N, int M, vector<int> A, vector<int> B, vector<int> P, vector<int> D, vector<int> C){
        n=N,m=M,cntp=2*n;
        rep(i,0,n-2)
            et[A[i]+1].push_back(B[i]+1),et[B[i]+1].push_back(A[i]+1);
        rep(i,1,m)
            p[i]=P[i-1]+1,d[i]=D[i-1],perc[p[i]].push_back(i);
        rep(i,1,n)
            c[i]=C[i-1];
        rep(i,1,m)
            id[i]=++cntp;
        tot=n,rt=0,maxs[0]=n+2,dfs1(1,0),dfz(rt);
        rep(i,1,n)
            e[i].push_back(mp(i+n,c[i]));
        dij();
        rep(i,1,m){
            if(dis[id[i]]==inf)ans.push_back(-1);
            else ans.push_back(dis[id[i]]);
        }
        return ans;
    }
    
    • 1

    信息

    ID
    10944
    时间
    4000ms
    内存
    1000MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者