• [BZOJ 3784] 树上的路径


    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=3784

    [算法]

           首先简单介绍一下点分治序列 :

           点分治序列和DFS序列,BFS序列等类似,是将点分治过程中每次的分治中心连在一起形成的序列,显然,点分治序列的长度是(N log N)的,那么,这个序列有什么用处呢? 当我们确定了一个分治中心后,与这个分治中心能形成一段路径的,必然是分治中心或是分治中心的一条链,是点分治序列

            中连续的一段

            在这题中,我们先求出点分治序列和每个节点与分治中心能形成路径的区间,再求出每个点到分治中心的距离,然后问题就由树上转化为了序列上 :

            在若干个数中,每个数都可以与它“控制”的一段区间的某个数相加,求前m个这样的最大的值

            这个问题可以用Sprase Table配合堆来解决

            时间复杂度 : O((N + M) log N)
    [代码]

           

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 50010
    #define MAXS 800010
    #define MAXLOG 20
    
    struct info
    {
        int val,pos,l,r;
        friend bool operator < (info a,info b)
        {
            return a.val < b.val;
        }
    } ;
    
    struct Edge
    {
        int to,w,nxt;
    } e[MAXN<<1];
    
    int i,j,n,m,pos,m1,m2,u,v,w,cnt,root,tot;
    int size[MAXN],weight[MAXN],head[MAXN],val[MAXS],l[MAXS],r[MAXS],sum[MAXS];
    int mx[MAXS][MAXLOG];
    bool visited[MAXN];
    priority_queue< info > q;
    info tmp;
    
    inline void addedge(int u,int v,int w)
    {
        cnt++;
        e[cnt] = (Edge){v,w,head[u]};
        head[u] = cnt;
    }
    inline void getroot(int u,int fa,int total)
    {
        int i,v;
        size[u] = 1;
        weight[u] = 0;
        for (i = head[u]; i; i = e[i].nxt)
        {
            v = e[i].to;
            if (fa != v && !visited[v])
            {
                getroot(v,u,total);
                size[u] += size[v];
                weight[u] = max(weight[u],size[v]);
            }
        }
        weight[u] = max(weight[u],total - size[u]);
        if (weight[u] < weight[root]) root = u;
    }
    inline void dfs(int u,int fa)
    {
        int i,v,w;
        tot++;
        val[tot] = sum[u];
        l[tot] = l[tot-1]; 
        if (!r[tot]) r[tot] = r[tot-1]; 
        for (i = head[u]; i; i = e[i].nxt)
        {
            v = e[i].to;
            w = e[i].w;
            if (v != fa && !visited[v])
            {
                sum[v] = sum[u] + w;
                dfs(v,u);
            }
        }
    }
    inline void work(int u)
    {
        int i,v,w;
        visited[u] = true;
        tot++;
        val[tot] = 0;
        l[tot] = tot; r[tot] = tot - 1;
        for (i = head[u]; i; i = e[i].nxt)
        {
            v = e[i].to;
            w = e[i].w;
            if (!visited[v]) 
            {
                sum[v] = w; 
                r[tot+1] = tot;
                dfs(v,u);
            }
        }    
        for (i = head[u]; i; i = e[i].nxt)
        {
            v = e[i].to;
            if (!visited[v])
            {
                root = 0;
                getroot(v,u,size[v]);
                work(root);
            }
        }
    }
    inline int my_max(int x,int y)
    {
        return (val[x] > val[y]) ? x : y;
    }
    inline int query(int l,int r)
    {
        if (l > r) return -1;
        int k = log(r - l + 1) / log(2.0);    
        return my_max(mx[l][k],mx[r-(1<<k)+1][k]);
    }
    
    int main()
    {
        
        scanf("%d%d",&n,&m);
        for (i = 1; i < n; i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        root = 0;
        size[0] = weight[0] = n;
        getroot(1,0,n);
        work(root);
        for (i = 1; i <= tot; i++) mx[i][0] = i;
        for (j = 1; (1 << j) <= tot; j++)
        {
            for (i = 1; i + (1 << j) - 1 <= tot; i++)    
            {
                mx[i][j] = my_max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
            }
        }
        for (i = 1; i <= tot; i++)
        {
            if (l[i] <= r[i])
                q.push((info){val[query(l[i],r[i])] + val[i],i,l[i],r[i]}); 
        }
        for (i = 1; i <= m; i++)
        {
            tmp = q.top();
            q.pop();
            printf("%d
    ",tmp.val);
            pos = query(tmp.l,tmp.r);
            m1 = query(tmp.l,pos-1);
            m2 = query(pos+1,tmp.r);
            if (m1 != -1) q.push((info){val[m1] + val[tmp.pos],tmp.pos,tmp.l,pos-1});
            if (m2 != -1) q.push((info){val[m2] + val[tmp.pos],tmp.pos,pos+1,tmp.r});
        }
        
        return 0;
    }

             

           

  • 相关阅读:
    如何在DOS中枚举PCI设备
    [Color]深入学习YCbCr色彩模型
    [Imm]Imm API学习笔记——输入法属性
    VBE_INFO(获取VBE信息)
    用VB写高效的图像处理程序 V2.0(2006524)
    ANSI环境下支持多语言输入的单行文本编辑器 V0.01
    分析外星人计算Pi的程序
    位运算模块mBit.bas
    [FileFormat]用VB写的高速GIF、JPEG 编码/解码 程序
    ANTLR笔记3 ANTLRWorks
  • 原文地址:https://www.cnblogs.com/evenbao/p/9329265.html
Copyright © 2020-2023  润新知