1 条题解

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

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Mr_Az
    我的尸体不会腐烂在泥土里,我会像鸟儿一样死在天空中。

    搬运于2025-08-24 23:13:36,当前版本为作者最后更新于2025-04-30 14:24:09,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    P12195 [NOISG 2025 Prelim] Itinerary

    Algorithm:

    树链剖分。

    Solution:

    赛时没切,大悲。

    由于树的性质:从 uuvv 的任意路径至少要经过其两点间最短路一次,加上我们遍历到的活动城市是要按顺序遍历的,所以我们可以猜测一个行程不合法的情况当且仅当沿着行程中相邻两点的最短路遍历的时候至少一条边被遍历了大于 22

    这个结论显然是正确的,因为其他在这个遍历顺序中没有遍历到的边都可以进去走一遍再出来,对结果并没有影响。

    于是我们要做的就是维护路径加,全局最小值,树链剖分即可。

    我们首先按顺序将活动行程中相邻两点的最短路加入,至于从不同城市出发,在活动行程的最开始加入 iis1s_1 的最短路判断最小值是否 2\le 2 即可。

    赛事没切的原因是忘记树链剖分的细节了,自己的实现出现了问题。

    时间复杂度:O(nlog2n)\text{O}(n \log^2 n)

    提供另外一个做法,发现这道题要做的就是将每一个城市作为活动行程的起点时,活动行程是否是以这个城市开头的欧拉序列的子序列。

    所以可以直接换根 DP,但是笔者没有实现。

    Code:

    void read(T &x, Args &... y){read(x);read(y...);}
    int n,m,ddfn;
    int s[N],dfn[N],ed[N],siz[N],son[N],top[N],dep[N],fa[N];
    vector<int> e[N];
    void dfs(int u,int fa){
        dep[u]=dep[fa]+1;siz[u]=1;::fa[u]=fa;
        int mx=0;
        for(auto v:e[u]){
            if(v==fa) continue;
            dfs(v,u);
            if(mx<siz[v]) son[u]=v,mx=siz[v];
            siz[u]+=siz[v];
        }
        return ;
    }
    void dfs1(int u,int fa,int t){
        top[u]=t;dfn[u]=++ddfn;
        if(!son[u]) return ;
        dfs1(son[u],u,t);
        for(auto v:e[u]){
            if(v!=fa&&v!=son[u]) dfs1(v,u,v);
        }
        // ed[u]=ddfn;
        return ;
    }
    inline bool in(int x,int y){return dfn[y]<=dfn[x]&&dfn[x]<=ed[y];}
    struct tree{
        int x,add;
        #define x(p) t[p].x
        #define add(p) t[p].add
    }t[N*4];
    #define mid (l+r>>1)
    inline void update(int p){x(p)=max(x(ls),x(rs));}
    inline void spread(int p){
        if(add(p)!=0){
            x(ls)+=add(p);
            x(rs)+=add(p);
            add(ls)+=add(p);add(rs)+=add(p);
            add(p)=0;
        }
        return ;
    }
    void addd(int p,int l,int r,int L,int R,int k){
        if(L>R) return ;
        if(L<=l&&r<=R){x(p)+=k;add(p)+=k;return ;}
        spread(p);
        if(L<=mid) addd(ls,l,mid,L,R,k);
        if(R>mid)  addd(rs,mid+1,r,L,R,k);
        update(p);
        return ;
    }
    int ask(int p,int l,int r,int L,int R){
        if(L>R) return 0;
        if(L<=l&&r<=R) return x(p);
        spread(p);
        int res=0;
        if(L<=mid) res=max(res,ask(ls,l,mid,L,R));
        if(R>mid)  res=max(res,ask(rs,mid+1,r,L,R));
        update(p);
        return res;
    }
    #undef x
    #undef mid
    #undef add
    inline bool add(int x,int y,int k){
        bool res=1;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            addd(1,1,n,dfn[top[x]],dfn[x],k);
            if(ask(1,1,n,1,n)>=3) res=0;
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        if(x!=y){
            addd(1,1,n,dfn[x]+1,dfn[y],k);
            if(ask(1,1,n,1,n)>=3) res=0;
        }
        return res;
    }
    signed main(){
        int st=clock();
        read(n,m);
        for(rint i=1,u,v;i<n;i++) read(u,v),e[u].pb(v),e[v].pb(u);
        dfs(1,0);ddfn=0;
        dfs1(1,0,1);
        for(rint i=1;i<=m;i++) read(s[i]);
        for(rint i=2;i<=m;i++){
            bool f=add(s[i-1],s[i],1);
            if(!f){for(rint i=1;i<=n;i++) puts("0");return 0;}
        }
        for(rint i=1;i<=n;i++){
            if(i==s[1]) puts("1");
            else{
                bool f=add(i,s[1],1);
                puts(f?"1":"0");
                add(i,s[1],-1);
            }
        }
        return 0;
    }
    
    
    • 1

    信息

    ID
    11895
    时间
    1000ms
    内存
    1024MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者