• #1490. 树上的路径


    题意
    内存限制:256 MiB
    时间限制:1000 ms

    给定一棵 $N$ 个结点的树,结点用正整数 $1…N$ 编号,每条边有一个正整数权值。用 $d(a,b)$ 表示从结点 $a$ 到结点 $b$ 路径上经过边的权值和,其中要求 $a<b$ 。将这 $frac{N imes (N-1)}{2}$ 个距离值从大到小排序,输出前 $M$ 个距离值。

    $N leq 50000$ , $M leq min(frac{N imes (N-1)}{2},300000)$
    题解
    考虑点分,建立出点分序,表示的时点分时经过的点,空间为 $O(n log n)$ ,每个点 $x$ 对应三元组 ${l,r,v}$ 表示 $x$ 点到重心的距离为 $v$ ,且可以取 $[l,r]$ 中的点组合形成一条链

    然后对于每个点找到其最长链并且加入堆中,形成四元组 ${l,r,max_{l,r},x}$ ,然后取出堆中的元素,并且找到 $max_{l,r}$ 所在的位置 $p$ ,并且将 ${l,p-1,max_{l,p-1},x}$ 和 ${p+1,r,max_{p+1,r},x}$ 加入堆中,循环 $m$ 次即可

    寻找最大值可用 $st$ 表实现

    代码

    #include <bits/stdc++.h>
    #define I inline
    using namespace std;
    const int N=5e4+5;bool vis[N];
    int n,m,sz[N],son[N],rt,o,hd[N],V[N*2];
    int W[N*2],nx[N*2],t,f[N*16][21],L,R,Lg[N*16];
    struct O{int l,r,v;}p[N*16];
    struct Q{
        int l,r,x,y;
        I friend bool operator < (Q A,Q B){
            return p[A.x].v+p[A.y].v<p[B.x].v+p[B.y].v;
        }
    };
    priority_queue<Q>q;
    I void add(int u,int v,int w){
        nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w;
    }
    #define v V[i]
    I void getrt(int x,int fa){
        sz[x]=1;son[x]=0;
        for (int i=hd[x];i;i=nx[i])
            if (v!=fa && !vis[v])
                getrt(v,x),sz[x]+=sz[v],
                son[x]=max(son[x],sz[v]);
        son[x]=max(o-sz[x],son[x]);
        if (son[x]<son[rt]) rt=x;
    }
    I void dfs(int x,int fa,int w){
        p[++t]=(O){L,R,w};f[t][0]=t;
        for (int i=hd[x];i;i=nx[i])
            if (v!=fa && !vis[v])
                dfs(v,x,w+W[i]);
    }
    I void work(int x){
        L=R=++t;f[t][0]=t;
        p[t]=(O){t,t,0};vis[x]=1;
        for (int i=hd[x];i;i=nx[i])
            if (!vis[v]) dfs(v,x,W[i]),R=t;
        for (int i=hd[x];i;i=nx[i])
            if (!vis[v])
                rt=0,o=sz[v],getrt(v,x),work(rt);
    }
    #undef v
    I int ax(int x,int y){
        return p[x].v>p[y].v?x:y;
    }
    I int query(int l,int r){
        int i=Lg[r-l+1];
        return ax(f[l][i],f[r-(1<<i)+1][i]);
    }
    I void push(int l,int r,int x){
        q.push((Q){l,r,x,query(l,r)});
    }
    int main(){
        son[0]=1e9;
        scanf("%d%d",&n,&m);
        for (int x,y,z,i=1;i<n;i++)
            scanf("%d%d%d",&x,&y,&z),
            add(x,y,z),add(y,x,z);
        t=0;o=n;getrt(1,0);work(rt);
        for (int i=2;i<=t;i++) Lg[i]=Lg[i>>1]+1;
        for (int i=t;i;i--)
            for (int j=1;i+(1<<j)<=t+1;j++)
                f[i][j]=ax(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        for (int i=1;i<=t;i++) push(p[i].l,p[i].r,i);
        while(m--){
            Q k=q.top();q.pop();
            printf("%d
    ",p[k.x].v+p[k.y].v);
            if (k.y>k.l) push(k.l,k.y-1,k.x);
            if (k.y<k.r) push(k.y+1,k.r,k.x);
        }
        return 0;
    }
  • 相关阅读:
    【CF1029A】Many Equal Substrings(模拟)
    【CF1028C】Rectangles(线段树)
    【CF1028B】Unnatural Conditions(构造)
    【CF1028A】Find Square(签到)
    【CF1025C】Plasticine zebra(模拟)
    【CF1025A】Doggo Recoloring(签到)
    167.数据传送指令
    166.寻址方式
    165.基础
    164.多媒体操作系统
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/10685667.html
Copyright © 2020-2023  润新知