HDU 4871 Shortest-path tree (树分治之点分治 最短路径树问题)

来源:互联网 发布:mac如何更改用户名称 编辑:程序博客网 时间:2024/05/29 05:57

题目大意:

给出一个连通的无向图, 然后找一颗生成树, 生成树满足点1到每个点的书上距离都是原图中的最短路, 然后在满足最短路的条件下, 点1到每个点的树上路径的序列字典序最小

找出这个树之后, 给出K询问树上有K个结点的路径的最大边权值, 以及这样的最大边权值的路径的方案数


大致思路:

首先spfa取得所有的1到其他点的最短距离

然后按照字典序进行dfs找出最短路径树

之后就是裸的树分治的问题了

用dis[i]表示i个结点的路径的最大长度, 用一个pre相加表示是否是当前层的子树的结果


代码如下:

Result  :  Accepted     Memory  :  7208 KB     Time  :  908 ms

/* * Author: Gatevin * Created Time:  2015/10/14 19:53:35 * File Name: Sakura_Chiyo.cpp */#include<iostream>#include<sstream>#include<fstream>#include<vector>#include<list>#include<deque>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<iomanip>using namespace std;const double eps(1e-8);typedef long long lint;#define maxn 30010int Test;int n, m, K;vector<pair<int, int> > T[maxn];//找出来的树vector<pair<int, int> > G[maxn];//原图int del[maxn];int root;int num;int mx[maxn];int size[maxn];int mi;void dfs_size(int now, int father){    size[now] = 1;    mx[now] = 0;    for(int i = 0, sz = T[now].size(); i < sz; i++)    {        int v = T[now][i].first;        if(v != father && !del[v])        {            dfs_size(v, now);            size[now] += size[v];            if(size[v] > mx[now]) mx[now] = size[v];        }    }}void dfs_root(int r, int now, int father){    if(size[r] - size[now] > mx[now]) mx[now] = size[r] - size[now];    if(mx[now] < mi) mi = mx[now], root = now;    for(int i = 0, sz = T[now].size(); i < sz; i++)    {        int v = T[now][i].first;        if(v != father && !del[v]) dfs_root(r, v, now);    }}bool vis[maxn];int d[maxn];const int inf = 1e9;void spfa()//跑点1到其他所有点的最短距离为d[]{    queue<int> Q;    Q.push(1);    memset(vis, 0, sizeof(vis));    fill(d, d + n + 1, inf);    vis[1] = 1, d[1] = 0;    while(!Q.empty())    {        int now = Q.front();        Q.pop();        vis[now] = 0;        for(int i = 0, sz = G[now].size(); i < sz; i++)        {            int v = G[now][i].first;            if(d[v] > d[now] + G[now][i].second)            {                d[v] = d[now] + G[now][i].second;                if(!vis[v]) vis[v] = 1, Q.push(v);            }        }    }}void getTree(int now){    for(int i = 0, sz = G[now].size(); i < sz; i++)        if(d[now] + G[now][i].second == d[G[now][i].first] && !vis[G[now][i].first])        {            vis[G[now][i].first] = 1;            T[now].push_back(G[now][i]);            T[G[now][i].first].push_back(make_pair(now, G[now][i].second));            getTree(G[now][i].first);        }}#define count motherfucklint dis[maxn];//dis[i]表示经过i个结点的路径最长的长度int count[maxn];//count[i]表示经过i个结点的路径最长的方案数int ans;//点数为K个点路径最大长度int cnt;//cnt表示dis[K]的答案方案数lint pre = 0;lint bit = 4e8;void get(int now, int father, int num, lint dep, int flag)//num表示经过点数,dep表示到根节点距离{    num++;    if(num >= K) return;    if(flag == 0)    {        if(dis[K - num] >= pre)        {            if(ans < (dis[K - num] - pre) + dep)                ans = dis[K - num] - pre + dep, cnt = count[K - num];            else if(ans == (dis[K - num] - pre) + dep)                cnt += count[K - num];        }    }    else    {        if(dis[num] >= pre)        {            if(dis[num] < pre + dep)            {                dis[num] = pre + dep;                count[num] = 1;            }            else if(dis[num] == pre + dep)                count[num]++;        }        else dis[num] = pre + dep, count[num] = 1;    }    for(int i = 0, sz = T[now].size(); i < sz; i++)    {        int v = T[now][i].first;        if(!del[v] && v != father)            get(v, now, num, dep + T[now][i].second, flag);    }}void dfs(int now){    mi = n;    dfs_size(now, 0);    dfs_root(now, now, 0);    del[root] = 1;    pre += bit;    dis[1] = pre;    count[1] = 1;    for(int i = 0, sz = T[root].size(); i < sz; i++)    {        int v = T[root][i].first;        if(!del[v])        {            get(v, root, 0, (lint)T[root][i].second, 0);            get(v, root, 1, (lint)T[root][i].second, 1);        }    }    int tmpRoot = root;    for(int i = 0, sz = T[tmpRoot].size(); i < sz; i++)    {        int v = T[tmpRoot][i].first;        if(!del[v])            dfs(v);    }}void solve(){    //pre = 0;    //memset(dis, 0, sizeof(dis));    spfa();    memset(vis, 0, sizeof(vis));    vis[1] = 1;    getTree(1);//把树找出来    ans = 0;    cnt = 0;    memset(del, 0, sizeof(del));    dfs(1);    printf("%d %d\n", ans, cnt);}int main(){    scanf("%d", &Test);    while(Test--)    {        scanf("%d %d %d", &n, &m, &K);        for(int i = 0; i <= n; i++) G[i].clear(), T[i].clear();        int u, v, w;        for(int i = 0; i < m; i++)        {            scanf("%d %d %d", &u, &v, &w);            G[u].push_back(make_pair(v, w));            G[v].push_back(make_pair(u, w));        }        for(int i = 1; i <= n; i++)            sort(G[i].begin(), G[i].end());        solve();    }    return 0;}/*22 1 21 2 3*/


0 0
原创粉丝点击