bzoj 3784: 树上的路径 堆维护第k大

3784: 树上的路径

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 88  Solved: 27
[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 )

  通过参见hzwer的博客意识到这道题可以用类似于超级钢琴的做法。然后猛然意识到超级钢琴大概在半年前就A掉了,但是现在根本不会做。。。。经过深刻反思决定一定要把这个算法记住,不能再忘记了。

  这是一种询问第k大值问题的经典思路,考虑用对维护,我们可以发现如果堆中存所有的状态会mle,然而有些状态一定会在其他状态被取之后才可能被取,于是乎我们将这些“继承”状态的插入移到其母状态取到后再加入。

  然后我犯了一个非常经典的错误,看起来好像是没啥问题,堆也应该是线性的,但是对于大数据由于多数状态lca都不是x,极多的continue导致算法退化为n^2。以后要理解清楚有贡献状态和忽略但占用时间复杂度的状态规模大小的比例。

  正解为先点分,然后每一层点分维护dfs序与距中心距离,令四元组[x,l,r,lev]表示在lev层路径左端点为x,右端点为当前层dfs序中l到r中任意一个的最大值,每次提取最值并将区间分成两个。通过线段树维护区间最大值和位置。时间复杂度O(nlogn),空间复杂度O(nlogn),大概就是这样吧。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define MAXN 51000
#define MAXV MAXN
#define MAXE MAXV*2
#define MAXT MAXN*40
#define INF 0x3f3f3f3f
#define smid ((l+r)>>1)
int n,m;
struct aaa
{
        int x,l,r;
        int lv;
        pair<int,int> mx;
};
bool operator < (const aaa& a1,const aaa& a2)
{
        return a1.mx<a2.mx;
}
struct sgt_node
{
        int lc,rc;
        pair<int,int> mx;
}sgt[MAXT];
int topt=0;
void Build_sgt(int &now,int l,int r,int v[])
{
        now=++topt;
        if (l==r)
        {
                sgt[now].mx=make_pair(v[l],l);
                return ;
        }
        Build_sgt(sgt[now].lc,l,smid,v);
        Build_sgt(sgt[now].rc,smid+1,r,v);
        if (sgt[sgt[now].lc].mx>sgt[sgt[now].rc].mx)
                sgt[now].mx=sgt[sgt[now].lc].mx;
        else
                sgt[now].mx=sgt[sgt[now].rc].mx;
}
pair<int,int> Query_sgt(int &now,int l,int r,int x,int y)
{
        if (l==x && r==y)
                return sgt[now].mx;
        if (y<=smid)
                return Query_sgt(sgt[now].lc,l,smid,x,y);
        else if (smid<x)
                return Query_sgt(sgt[now].rc,smid+1,r,x,y);
        else
                return max(Query_sgt(sgt[now].lc,l,smid,x,smid),Query_sgt(sgt[now].rc,smid+1,r,smid+1,y));

}

struct Edge
{
        int np,val;
        int id;
        Edge *next;
}E[MAXE],*V[MAXV];
int tope=-1;
void addedge(int x,int y,int z,int id)
{
        E[++tope].np=y;
        E[tope].val=z;
        E[tope].id=id;
        E[tope].next=V[x];
        V[x]=&E[tope];
}
int elev[MAXE];
int pnt[MAXN];
int q[MAXN];
int siz[MAXN];
int get_core(int now)
{
        Edge *ne;
        int head=-1,tail=0;
        q[0]=now;
        pnt[now]=now;
        while (head<tail)
        {
                now=q[++head];
                for (ne=V[now];ne;ne=ne->next)
                {
                        if (ne->np==pnt[now] || ~elev[ne->id])continue;
                        q[++tail]=ne->np;
                        pnt[ne->np]=now;
                }
        }
        for (register int i=tail;i>=0;i--)
        {
                now=q[i];
                siz[now]=1;
                for (ne=V[now];ne;ne=ne->next)
                {
                        if (ne->np==pnt[now] || ~elev[ne->id])continue;
                        siz[now]+=siz[ne->np];
                }
        }
        int ret;
        int mxsiz=0,bstsiz=INF;
        if (siz[q[0]]==1)return -1;
        for (register int i=0;i<=tail;i++)
        {
                now=q[i];
                mxsiz=siz[q[0]]-siz[now];
                for (ne=V[now];ne;ne=ne->next)
                {
                        if (ne->np==pnt[now] || ~elev[ne->id])continue;
                        mxsiz=max(mxsiz,siz[ne->np]);
                }
                if (bstsiz>mxsiz)
                {
                        bstsiz=mxsiz;
                        ret=now;
                }
        }
        return ret;
}
int seq[20][MAXN];
int cdis[20][MAXN];
int totsq[20];
int stack[MAXN],tops=-1;
void dfs1(int now,int dist,int lev,int p)
{
        register Edge *ne;
        seq[lev][totsq[lev]]=now;
        cdis[lev][totsq[lev]]=dist;
        totsq[lev]++;
        stack[++tops]=now;
        for (ne=V[now];ne;ne=ne->next)
        {
                if (~elev[ne->id] || ne->np==p)continue;
                dfs1(ne->np,dist+ne->val,lev,now);
        }
}
aaa stacka[MAXN*40];
int topsa=-1;
void solve(int now,int lev)
{
        int core=get_core(now);
        int tsiz=siz[q[0]];
        if (tsiz==1)return ;
        register Edge *ne;
        for (ne=V[core];ne;ne=ne->next)
                if (elev[ne->id]==-1)
                        elev[ne->id]=lev;
        int a,b;
        aaa at;
        at.lv=lev;
        a=totsq[lev];
        seq[lev][totsq[lev]]=core;
        cdis[lev][totsq[lev]]=0;
        totsq[lev]++;
        for (ne=V[core];ne;ne=ne->next)
        {
                if (elev[ne->id]!=lev)continue;
                tops=-1;
                b=totsq[lev];
                dfs1(ne->np,ne->val,lev,core);
                for (register int i=b;i<totsq[lev];i++)
                {
                        at.x=i;
                        at.l=a;
                        at.r=b-1;
                        if (at.l<=at.r)stacka[++topsa]=at;
                }
        }
        for (ne=V[core];ne;ne=ne->next)
        {
                if (elev[ne->id]!=lev)continue;
                solve(ne->np,lev+1);
        }
}
int root[20];
aaa heap[MAXN*50];
int toth=0;
int main()
{
        freopen("input.txt","r",stdin);
        freopen("output.txt","w",stdout);
        int x,y,z;
        scanf("%d%d",&n,&m);
        for (int i=1;i<n;i++)
        {
                scanf("%d%d%d",&x,&y,&z);
                addedge(x,y,z,i);
                addedge(y,x,z,i);
        }
        memset(elev,-1,sizeof(elev));
        solve(1,0);
        for (int i=0;i<20;i++)
                if (totsq[i])
                        Build_sgt(root[i],0,totsq[i]-1,cdis[i]);

        pair<int,int> pr;
        while (~topsa)
        {
                x=cdis[stacka[topsa].lv][stacka[topsa].x];
                stacka[topsa].mx=Query_sgt(root[stacka[topsa].lv],0,totsq[stacka[topsa].lv]-1,stacka[topsa].l,stacka[topsa].r);
                stacka[topsa].mx.first+=x;
                heap[toth]=stacka[topsa--];
                push_heap(heap,heap+(++toth));
        }
        int rnow=0;
        aaa at,at2;
        while (rnow<m)
        {
                at=heap[0];
                pop_heap(heap,heap+(toth--));
                rnow++;
                printf("%d
",at.mx.first);
                at2=at;
                at2.r=at2.mx.second-1;
                if (at2.l<=at2.r)
                {
                        x=cdis[at2.lv][at2.x];
                        at2.mx=Query_sgt(root[at2.lv],0,totsq[at2.lv]-1,at2.l,at2.r);
                        at2.mx.first+=x;
                        heap[toth]=at2;
                        push_heap(heap,heap+(++toth));
                }
                at2=at;
                at2.l=at2.mx.second+1;
                if (at2.l<=at2.r)
                {
                        x=cdis[at2.lv][at2.x];
                        at2.mx=Query_sgt(root[at2.lv],0,totsq[at2.lv]-1,at2.l,at2.r);
                        at2.mx.first+=x;
                        heap[toth]=at2;
                        push_heap(heap,heap+(++toth));
                }
        }
}
原文地址:https://www.cnblogs.com/mhy12345/p/4372871.html