• bzoj3784 树上的路径


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3784

    【题解】

    和超级钢琴很像啊。

    一看题目,无脑点分。

    那么我们发现点分的路径形式和“超级钢琴”的哪个很像啊。

    点分是子树合并对吧,当前子树内的每个点都能选择前面子树的区间,那么跟“超级钢琴”不同的就是这个是加的。

    那么点分治维护即可。距离似乎(?)不会太多,那么我们套用那个堆的做法就行。

    upd:距离最多nlogn个。

    # include <queue> 
    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
     
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10, N = 1e6 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    
    int n, m;
    int head[M], nxt[M], to[M], tot=0, w[M];
    inline void add(int u, int v, int _w) {
        ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; w[tot] = _w; 
    }
    inline void adde(int u, int v, int _w) {
        add(u, v, _w), add(v, u, _w);
    }
    
    int val[N], L[N], R[N], tn = 0; 
    
    namespace DFZ {
        bool vis[M]; 
        int sz[M], mx[M];
        inline void getsize(int x, int fa=0) {
            sz[x] = 1, mx[x] = 0;
            for (int i=head[x]; i; i=nxt[i]) {
                if(to[i] == fa || vis[to[i]]) continue;
                getsize(to[i], x);
                sz[x] += sz[to[i]];
                if(sz[to[i]] > mx[x]) mx[x] = sz[to[i]]; 
            }
        }
        int mi, centre;
        inline void getcentre(int x, int tp, int fa=0) {
            if(sz[tp] - sz[x] > mx[x]) mx[x] = sz[tp] - sz[x];
            if(mx[x] < mi) mi = mx[x], centre = x;
            for (int i=head[x]; i; i=nxt[i]) {
                if(to[i] == fa || vis[to[i]]) continue;
                getcentre(to[i], tp, x);
            }
        }
        int curl, curr;
        
        inline void calc(int x, int fa, int dis) {
            val[++tn] = dis, L[tn] = curl, R[tn] = curr; 
            for (int i=head[x]; i; i=nxt[i]) 
                if(to[i] != fa && !vis[to[i]]) calc(to[i], x, dis+w[i]);
        }
        
        inline void dfs(int x) {
            getsize(x); mi=n; getcentre(x, x);
            x = centre;
            
            ++tn;
            curl = curr = tn;
            
            for (int i=head[x]; i; i=nxt[i]) 
                if(!vis[to[i]]) calc(to[i], x, w[i]), curr = tn; 
            
            vis[x] = 1;
            for (int i=head[x]; i; i=nxt[i]) 
                if(!vis[to[i]]) dfs(to[i]); 
        }
    }
    
    namespace ST {
        struct rmq {
            int i, v;
            rmq() {}
            rmq(int i, int v) : i(i), v(v) {}
            friend bool operator <(rmq a, rmq b) {
                return a.v<b.v;
            }
            friend bool operator >(rmq a, rmq b) {
                return a.v>b.v;
            }
        };
        int n, Log2[N];
        rmq f[N][21];
        inline void init(int _n) {
            n = _n;
            Log2[1] = 0;
            for (int i=2; i<=n; ++i) Log2[i] = Log2[i>>1] + 1;
            for (int i=1; i<=n; ++i) f[i][0] = rmq(i, val[i]);
            for (int j=1; j<=20; ++j)
                for (int i=1; i+(1<<j)-1<=n; ++i) 
                     f[i][j] = max(f[i][j-1], f[i+(1<<(j-1))][j-1]);
        }
        inline bool getpos(int l, int r, int &i, int &v) {
            if(l > r) return 0;
            int len = Log2[r-l+1];
            rmq t = max(f[l][len], f[r-(1<<len)+1][len]);
            i = t.i, v = t.v;
            return 1;
        }
    }
    
    
    struct pa {
        int x, l, r, mx, v; 
        pa() {}
        pa(int x, int l, int r, int mx, int v) : x(x), l(l), r(r), mx(mx), v(v) {}
        friend bool operator < (pa a, pa b) {
            return a.v<b.v;
        }    
    };
    
    priority_queue<pa> q;
    
    int main() {
        scanf("%d%d", &n, &m); 
        for (int i=1, u, v, _w; i<n; ++i) {
            scanf("%d%d%d", &u, &v, &_w);
            adde(u, v, _w);
        }
        DFZ::dfs(1); 
        ST::init(tn); 
        while(!q.empty()) q.pop();
        for (int i=1; i<=tn; ++i) {
            int va, po;
            ST::getpos(L[i], R[i], po, va);
            q.push(pa(i, L[i], R[i], po, va+val[i])); 
        }
        for (int i=1; i<=m; ++i) {
            pa t = q.top(); 
            printf("%d
    ", t.v); 
            q.pop(); 
            int va, po;
            if(ST::getpos(t.l, t.mx-1, po, va)) 
                q.push(pa(t.x, t.l, t.mx-1, po, val[t.x]+va));
            if(ST::getpos(t.mx+1, t.r, po, va))
                q.push(pa(t.x, t.mx+1, t.r, po, val[t.x]+va));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    apache、php隐藏http头部版本信息的实现方法
    CentOs 设置静态IP 方法
    PHP如何判断远程图片文件是否存在
    linux删除乱码文件
    Linux基础学习1
    C#——继承
    解决简体输出乱码问题
    简单的Tuple声明和输出
    懒汉式与饿汉式的区别
    Java 反射
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3784.html
Copyright © 2020-2023  润新知