zoukankan      html  css  js  c++  java
  • HDU 4871 Shortest-path tree

    先用dijkstra把最短路树建出来,然后就是树的质心分治了。

    经过k个点的路径,要么全在子树上,要么经过根结点,因此可以分治。

    如果分治的时候选点不好会变成O(n^2),比较极端的情况是比如树是一条链。

    选择质心可以保证最大子树结点不超过n/2,每次递归至少减半,递归层数是O(logn)的。

    找子树质心是O(n)的树形dp,枚举到根结点的路径是O(n)的。

    把经过根节点并且路径上有c个结点的最长路径以及方案保存到一个map,对于一条新增的路径去查找k-c个点的路径,就可以更新答案了。

    如果用的unorder_map,那么查找是O(1)的,因此分治复杂度是T(n) = 2*T(n/2) + O(n) ≈ O(nlogn)。

    总体复杂度是O(mlogn + nlogn)

    /*********************************************************
    *            ------------------                          *
    *   author AbyssFish                                     *
    **********************************************************/
    #include<cstdio>
    #include<iostream>
    #include<string>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<stack>
    #include<map>
    #include<set>
    #include<algorithm>
    #include<cmath>
    #include<numeric>
    #include<climits>
    #include<unordered_map>
    using namespace std;
    
    const int maxn = 30000+2;
    const int maxm = 60000*2+3;
    
    typedef long long ll;
    #define sInt 4
    int hd[maxn], nx[maxm], to[maxm], we[maxm], ec;
    #define eachedge int i = hd[u]; ~i; i = nx[i]
    void init_g(int n){ memset(hd+1,0xff,sInt*n); ec = 0; }
    void add_edge(int u,int v,int c)
    {
        to[ec] = v;
        we[ec] = c;
        nx[ec] = hd[u];
        hd[u] = ec++;
    }
    
    int n,m,k;
    
    int di[maxn], fe[maxn];
    typedef pair<int,int> pii;
    #define dist first
    #define ver second
    priority_queue<pii,vector<pii>,greater<pii> > q;
    
    void dijkstra()
    {
        memset(di+1,0x3f,sInt*n);
    
        di[1] = 0; fe[1] = -1;
        q.push(pii(0,1));
        while(!q.empty()){
            pii x = q.top(); q.pop();
            if(x.dist != di[x.ver]) continue;
            int u = x.ver;
            for(int i = hd[u]; ~i; i = nx[i]){
                int v = to[i];
                if(di[v] > di[u] + we[i]){
                    di[v] = di[u]+we[i];
                    fe[v] = i;
                    q.push(pii(di[v],v));
                }
                else if(di[v] == di[u] + we[i] && to[fe[v]^1] > u){
                    fe[v] = i;
                }
            }
        }
    }
    
    
    void rewrite(int u,int i)
    {
        nx[i] = hd[u];
        hd[u] = i;
    }
    
    void build_tree()
    {
        dijkstra();
        init_g(n);
        for(int v = 2; v <= n; v++){
            int e = fe[v];
            int u = to[e^1];
            rewrite(u,e);
            rewrite(v,e^1);
        }
    }
    
    bool vis_c[maxn];
    int tr_sz[maxn];
    
    void cal_tr_sz(int u,int f)
    {
        int &c = tr_sz[u];
        c = 1;
        for(eachedge){
            int v = to[i];
            if(v == f || vis_c[v]) continue;
            c += tr_sz[v];
            cal_tr_sz(v,u);
        }
    }
    
    int block_size;
    int best, centroid;
    void findCentroid(int u,int f)
    {
        int mx = 0;
        for(eachedge){
            int v = to[i];
            if(v == f || vis_c[v]) continue;
            findCentroid(v,u);
            mx = max(mx, tr_sz[v]);
        }
        mx = max(mx,block_size-tr_sz[u]);
        if(best > mx){
            best = mx;
            centroid = u;
        }
    }
    
    typedef unordered_map<int,pii> cont;
    typedef cont::iterator con_it;
    //key 经过的点数,value(最长距离,方案数)
    cont prv;
    cont tmp;
    
    
    void update(cont &res,int c, const pii &np)
    {
        con_it it = res.find(c);
        if(it != res.end()){
            pii &p = it->second;
            if(p.dist == np.dist) p.ver += np.ver;
            else if(p.dist < np.dist) {
                p = np;
            }
        }
        else {
            res.insert(make_pair(c,np));
        }
    }
    
    void enum_path(int u,int f,int c,int d,cont &res)
    {
        if(c >= k) return;
        update(res,c,pii(d,1));
    
        for(eachedge){
            int v = to[i];
            if(v == f || vis_c[v]) continue;
            enum_path(v,u,c+1,d+we[i],res);
        }
    }
    
    int ans;
    ll cnt;
    
    void divide(int rt)
    {
        cal_tr_sz(rt,-1);
        best = INT_MAX;
        block_size = tr_sz[rt];
        findCentroid(rt,-1);
        int u = centroid;
        vis_c[u] = true;
    
        for(eachedge){
            if(!vis_c[to[i]]) divide(to[i]);
        }
    
        prv.clear();
        prv.insert(make_pair(1,pii(0,1)));
        for(eachedge){
            if(vis_c[to[i]]) continue;
            tmp.clear();
            enum_path(to[i],u,1,we[i],tmp);
            con_it it, it2;
            for(it = tmp.begin(); it != tmp.end(); it++){
                int c = it->first;
                pii &p = it->second;
                if((it2 = prv.find(k-c)) != prv.end()){
                    ll dis = it2->second.dist + p.dist;
                    if(dis > ans){
                        ans = dis; cnt = p.ver * it2->second.ver;
                    }
                    else if(dis == ans) cnt += p.ver * it2->second.ver;
                }
            }
    
            for(it = tmp.begin(); it != tmp.end(); it++){
                int c = it->first+1;
                update(prv,c,it->second);
            }
        }
    
        vis_c[u] = false;
    }
    
    void solve()
    {
        build_tree();
        ans = cnt = 0;
        divide(1);
        printf("%d %lld
    ",ans,cnt);
    }
    
    
    void init()
    {
        scanf("%d%d%d",&n,&m,&k);
        init_g(n);
        for(int i = 0; i < m; i++){
            int a,b,c; scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
            add_edge(b,a,c);
        }
    }
    
    
    //#define LOCAL
    int main()
    {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif
        int T; scanf("%d",&T);
        while(T--){
            init();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    CSP模拟11
    P3870 [TJOI2009]开关
    P2357 守墓人(分块)
    那一天她离我而去 (最短路)
    礼物(概率dp)
    收集邮票(概率dp)
    齿轮
    water
    【纪中受难记】——C3D4:万里无云
    zz maven eclipse svn 上传下载
  • 原文地址:https://www.cnblogs.com/jerryRey/p/5026711.html
Copyright © 2011-2022 走看看