zoukankan      html  css  js  c++  java
  • 【BZOJ-3784】树上的路径 点分治 + ST + 堆

    3784: 树上的路径

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 462  Solved: 153
    [Submit][Status][Discuss]

    Description

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

    Input

    第一行两个正整数N,M
    下面N-1行,每行三个正整数a,b,c(a,b<=N,C<=10000)。表示结点a到结点b有一条权值为c的边。

    Output

    共M行,如题所述.

    Sample Input

    5 10
    1 2 1
    1 3 2
    2 4 3
    2 5 4

    Sample Output

    7
    7
    6
    5
    4
    4
    3
    3
    2
    1

    HINT

    N<=50000,M<=Min(300000,n*(n-1) /2 

    Source

    Solution

    超级钢琴推广到树上版本

    利用点分治每个点的时间戳,将树转化到序列上,顺带记录每个节点,能和他组成一条路径的左右端点L,R

    然后利用超级钢琴的方法去处理就好,具体见这里

    Code

    #include<iostream> 
    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
    #include<queue> 
    using namespace std; 
    int read() 
    { 
        int x=0,f=1; char ch=getchar(); 
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} 
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} 
        return x*f; 
    } 
    #define MAXN 100010 
    #define MAXM 1000100 
    int N,M; 
    struct EdgeNode{int next,to,val;}edge[MAXN<<1]; 
    int head[MAXN],cnt=1; 
    void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].val=w;} 
    void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);} 
    int maxx[MAXN],size[MAXN],Sz,root,L[MAXM],R[MAXM],D[MAXM],pl,pr,dfn; 
    bool visit[MAXN]; 
    void DFSRoot(int now,int last) 
    { 
        size[now]=1; maxx[now]=0; 
        for (int i=head[now]; i; i=edge[i].next) 
            if (edge[i].to!=last && !visit[edge[i].to]) 
                { 
                    DFSRoot(edge[i].to,now); 
                    size[now]+=size[edge[i].to]; 
                    maxx[now]=max(maxx[now],size[edge[i].to]); 
                } 
        maxx[now]=max(maxx[now],Sz-size[now]); 
        if (maxx[now]<maxx[root]) root=now; 
    } 
    void Get(int x,int last,int Dis) 
    { 
        D[++dfn]=Dis; L[dfn]=pl,R[dfn]=pr; 
        for (int i=head[x]; i; i=edge[i].next) 
            if (!visit[edge[i].to] && edge[i].to!=last) 
                Get(edge[i].to,x,Dis+edge[i].val); 
    } 
    void Divide(int x) 
    { 
        visit[x]=1; 
        pl=pr=++dfn; 
        for (int i=head[x]; i; i=edge[i].next) 
            if (!visit[edge[i].to]) Get(edge[i].to,x,edge[i].val),pr=dfn; 
        for (int i=head[x]; i; i=edge[i].next) 
            if (!visit[edge[i].to])  
                { 
                    Sz=size[edge[i].to]; root=0; 
                    DFSRoot(edge[i].to,x); 
                    Divide(root); 
                } 
    } 
    int log2[MAXM],dp[20][MAXM]; 
    int Max(int x,int y) {return D[x]>D[y]? x:y;} 
    void ST() 
    { 
        log2[0]=-1; 
        for (int i=1; i<=N; i++) 
            if (i&(i-1)) log2[i]=log2[i-1]; else log2[i]=log2[i-1]+1; 
        for (int i=1; i<=dfn; i++) dp[0][i]=i; 
        for (int j=1; (1<<j)<=dfn; j++) 
            for (int i=1; i+(1<<j)-1<=dfn; i++) 
                dp[j][i]=Max(dp[j-1][i],dp[j-1][i+(1<<j-1)]); 
    } 
    inline int RMQ(int l,int r) 
    { 
        int tmp=log2[r-l+1]; 
        return Max(dp[tmp][l],dp[tmp][r-(1<<tmp)+1]);  
    } 
    struct HeapNode 
    { 
        int ip,L,R,pos; 
        HeapNode (int ip=0,int L=0,int R=0,int pos=0) 
            : ip(ip),L(L),R(R),pos(pos) {} 
        bool operator < (const HeapNode & A) const
            {return D[ip]+D[pos]<D[A.ip]+D[A.pos];} 
    }; 
    priority_queue<HeapNode>heap; 
    int main() 
    { 
        N=read(),M=read(); 
        for (int x,y,z,i=1; i<=N-1; i++) x=read(),y=read(),z=read(),InsertEdge(x,y,z); 
        maxx[root=0]=Sz=N; 
        DFSRoot(1,0); 
        Divide(root); 
        ST(); 
        for (int i=1; i<=dfn; i++) 
            heap.push( HeapNode(i,L[i],R[i],RMQ(L[i],R[i])) ); 
        while (M--) 
            { 
                HeapNode now=heap.top(); heap.pop(); 
                printf("%d
    ",D[now.ip]+D[now.pos]); 
                HeapNode ls=now; ls.R=now.pos-1; 
                if (ls.R>=ls.L) ls.pos=RMQ(ls.L,ls.R),heap.push(ls); 
                HeapNode rs=now; rs.L=now.pos+1; 
                if (rs.R>=rs.L) rs.pos=RMQ(rs.L,rs.R),heap.push(rs);      
            } 
        return 0; 
    }

    一天前刚写超级钢琴,写起来就非常顺畅了

  • 相关阅读:
    Oracle SQL语句大全—查看表空间
    Class to disable copy and assign constructor
    在moss上自己总结了点小经验。。高手可以飘过 转贴
    在MOSS中直接嵌入ASP.NET Page zt
    Project Web Access 2007自定义FORM验证登录实现 zt
    SharePoint Portal Server 2003 中的单一登录 zt
    vs2008 开发 MOSS 顺序工作流
    VS2008开发MOSS工作流几个需要注意的地方
    向MOSS页面中添加服务器端代码的另外一种方式 zt
    状态机工作流的 SpecialPermissions
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5789620.html
Copyright © 2011-2022 走看看