BZOJ4016 最短路径树问题

  给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。

Input

第一行输入三个正整数n,m,K,表示有n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci<=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。
 
 

Output

  输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。
 

Sample Input

  6 6 4

  1 2 1

  2 3 1

  3 4 1

  2 5 1

  3 6 1

  5 6 1

Sample Output

  3 4

Hint

  对于所有数据n<=30000,m<=60000,2<=K<=n。
  数据保证最短路径树上至少存在一条长度为K的路径。
  2016.12.7新加数据一组by - wyx-150137

题解

首先我们先建立最短路径树(dijkstra+dfs),让后对最短路径树做点分治,f[i][j][2]:表示前i个子树到根节点距离为j  {0:表示最大距离   1:表示当前最大距离的路径数}
对与新加的子树,做一边相同操作后,更新f即可.

参考代码

#include<bits/stdc++.h>
using namespace std;
#define PI acos(-1.0)
#define pii pair<int,int>
#define mkp make_pair
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=60010;

int n,m,k;
vector<pii> v[maxn];
int head[maxn],h[maxn],vis[maxn],fa[maxn],cnt1,cnt;
int f[maxn][2],g[maxn][2];
int dis[maxn],deep[maxn];
int rt,sum,S,mx[maxn],size[maxn];
int ans1,ans2;

struct Edge{
    int v,w,nxt;
} edge[maxn<<1],e[maxn<<1];

void addedge(int u,int v,int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt++;
}

void addedge1(int u,int v,int w)
{
    e[cnt1].v=v;
    e[cnt1].w=w;
    e[cnt1].nxt=h[u];
    h[u]=cnt1++;
}

void dijkstra()
{
    priority_queue<pii,vector<pii>,greater<pii> > q;
    q.push(make_pair(0,1));
    for(int i=2;i<=n;++i) dis[i]=INF;
    dis[1]=0;
    while(!q.empty())
    {
        int u=q.top().second; 
        int x=q.top().first;q.pop();
        if(dis[u]!=x) continue;
        for(int i=head[u];~i;i=edge[i].nxt)
        {
            int V=edge[i].v;
            if(dis[u]+edge[i].w<dis[V])
            {
                dis[V]=dis[u]+edge[i].w;
                q.push(make_pair(dis[V],V));
            }
        }
    }
    
}

void dfs(int u)
{
    vis[u]=1;
    for(int i=head[u];~i;i=edge[i].nxt)
    {
        int v=edge[i].v;
        if(!vis[v] && dis[u]+edge[i].w==dis[v])
        {
            addedge1(u,v,edge[i].w);
            addedge1(v,u,edge[i].w);
            dfs(v);
        }
    }
}

void getroot(int u)
{
    size[u]=1;mx[u]=0;
    for(int i=h[u];~i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v!=fa[u] && !vis[v])
        {
            fa[v]=u;
            getroot(v);
            mx[u]=max(mx[u],size[v]);
            size[u]+=size[v];
        }
    }
    mx[u]=max(mx[u],sum-size[u]);
    if(mx[u]<mx[rt]) rt=u;
}

void solve(int x,int S)
{
    vis[x]=1; f[0][1]=1;
    
    for(int i=h[x];~i;i=e[i].nxt)
    {
        if(!vis[e[i].v])
        {
            int hed=0,tail=0,q[maxn];
            q[tail++]=e[i].v;
            fa[e[i].v]=x;
            dis[e[i].v]=e[i].w;
            deep[e[i].v]=1;
            
            while(hed!=tail)
            {
                int now=q[hed++];
                int K=deep[now];
                if(K>k) break;
                if(dis[now]>g[K][0]) g[K][0]=dis[now],g[K][1]=0;
                if(dis[now]==g[K][0]) g[K][1]++;
                
                for(int j=h[now];~j;j=e[j].nxt)
                {
                    int v=e[j].v;
                    if(!vis[e[j].v] && e[j].v!=fa[now])
                    {    
                        fa[v]=now;
                        deep[v]=deep[now]+1;
                        dis[v]=dis[now]+e[j].w;
                        q[tail++]=v;
                    }
                }
            }
            
            for(int j=1;j<=k;++j) 
            {
                if(g[j][0]+f[k-j][0]>ans1) ans1=g[j][0]+f[k-j][0],ans2=0;
                if(g[j][0]+f[k-j][0]==ans1) ans2+=g[j][1]*f[k-j][1];
            }

            for(int j=1;j<=k;++j) 
            {
                if(g[j][0]>f[j][0]) f[j][0]=g[j][0],f[j][1]=0;
                if(g[j][0]==f[j][0]) f[j][1]+=g[j][1];
                g[j][0]=g[j][1]=0;
            }
        }
    }
    
    for(int j=0;j<=k;++j) f[j][0]=f[j][1]=0;
    
    for(int j=h[x];~j;j=e[j].nxt)
    {
        if(!vis[e[j].v])
        {
            sum=size[e[j].v];
            if(size[e[j].v]>size[x]) sum=S-size[x];
            rt=0;
            if(sum>=k) getroot(e[j].v);
            solve(rt,size[e[j].v]);
        }
    }
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int x,y,z;k--;
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&x,&y,&z);
        v[x].push_back(make_pair(y,z));
        v[y].push_back(make_pair(x,z));
    }
    
    cnt=cnt1=ans1=0;
    memset(head,-1,sizeof(head));
    memset(h,-1,sizeof(h));
    memset(vis,0,sizeof(vis));
    
    for(int i=1;i<=n;++i)
    {
        sort(v[i].begin(),v[i].end());
        for(int j=v[i].size()-1;j>=0;--j)
            addedge(i,v[i][j].first,v[i][j].second);
    }
    
    dijkstra();
    dfs(1);
    
    memset(vis,0,sizeof(vis));
    rt=0;mx[0]=INF;sum=n;
    getroot(1);
    solve(rt,sum);
    
    printf("%d %d\n",ans1,ans2);
    
    return 0;
}
View Code

 

 

 

posted @ 2019-05-25 19:25  StarHai  阅读(395)  评论(0编辑  收藏  举报