• Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)


    题面

    Bzoj

    洛谷

    题解

    首先把最短路径树建出来(用$Dijkstra$,没试过$SPFA$$leftarrow$它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我们用点分治来做(滑稽)。

    有一点要说,这一题数据比较水,如果不用字典序的话,也可以过。如何建立字典序呢?其实我们从$1$号节点开始遍历路径树(不是最短路径树),令一个点的第一关键字是点权,如果点权相等就按照编号大小为第二关键字,维护一个二元组就好了。

    点分治时记两个数组$S[i]$和$num[i]$,表示经过$i$个点的路径最大是多少以及在这个情况下有多少条路径。

    之前找重心调了好久。

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <iostream>
    using std::pair; using std::sort;
    using std::priority_queue;
    using std::vector; using std::greater;
    typedef long long ll;
    typedef pair<int, int> pii;
    
    template<typename T>
    void read(T &x) {
        int flag = 1; x = 0; char ch = getchar();
        while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
        while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
    }
    
    const int N = 3e4 + 10, Inf = 1 << 30;
    int n, m, k, from[N], dist[N], MX, tot;
    int cnt, to[N << 1], nxt[N << 1], dis[N << 1];
    bool vis[N];
    vector<pii> G[N]; priority_queue< pii, vector<pii>, greater<pii> > q;
    void addEdge(int u, int v, int w) {
    	to[++cnt] = v, nxt[cnt] = from[u], dis[cnt] = w, from[u] = cnt;
    }
    
    void dijk(int s) {
    	memset(dist, 0x7777777f, sizeof dist);
    	dist[s] = 0, q.push((pii){0, s});
    	while(q.size()) {
    		int u = q.top().second; q.pop();
    		if(vis[u]) continue; vis[u] = true;
    		for(int i = 0; i < G[u].size(); ++i) {
    			int v = G[u][i].first, w = G[u][i].second + dist[u];
    			if(dist[v] > w) dist[v] = w, q.push((pii){dist[v], v});
    		}
    	}
    }
    
    void init(int u) {
    	vis[u] = 1;
    	for(int i = 0; i < G[u].size(); ++i) {
    		int v = G[u][i].first, w = G[u][i].second;
    		if(vis[v] || w + dist[u] != dist[v]) continue;
    		addEdge(u, v, w), addEdge(v, u, w), init(v);
    	}
    }
    
    int Size, tmp, p, siz[N], maxnow, S[N], num[N];
    inline void upt(int &a, int b) { if(a < b) a = b; }
    
    void getrt(int u, int f) { 
    	int max_part = 0; siz[u] = 1;
    	for(int i = from[u]; i; i = nxt[i]) {
    		int v = to[i]; if(vis[v] || v == f) continue;
    		getrt(v, u); siz[u] += siz[v];
    		upt(max_part, siz[v]);
    	} upt(max_part, Size - siz[u]);
    	if(max_part < tmp) p = u, tmp = max_part;
    }
    
    void calc(int u, int f, int now) {
    	upt(maxnow, now);
    	if(now == k - 1) {
    		if(dist[u] == MX) ++tot;
    		else if(dist[u] > MX) MX = dist[u], tot = 1;
    		return ;
    	}
    	int nowans = -1;
    	if(S[k - 1 - now] != -1) nowans = dist[u] + S[k - 1 - now];
    	if(nowans == MX) tot += num[k - 1 - now];
    	else if(nowans > MX) MX = nowans, tot = num[k - 1 - now];
    	for(int i = from[u]; i; i = nxt[i]) {
    		int v = to[i]; if(vis[v] || v == f) continue;
    		dist[v] = dist[u] + dis[i], calc(v, u, now + 1);
    	}
    }
    
    void update(int u, int f, int now) {
    	if(now == k - 1) return ;
    	if(S[now] == dist[u]) ++num[now];
    	else upt(S[now], dist[u]), num[now] = 1;
    	for(int i = from[u]; i; i = nxt[i]) {
    		int v = to[i]; if(vis[v] || v == f) continue;
    		update(v, u, now + 1);
    	}
    }
    
    void doit(int x) {
    	p = 0, tmp = Inf, getrt(x, 0), vis[p] = 1, maxnow = 0;
    	for(int i = from[p]; i; i = nxt[i]) {
    		int v = to[i]; if(vis[v]) continue;
    		dist[v] = dis[i], calc(v, p, 1), update(v, p, 1);
    	}
    	for(int i = 1; i <= maxnow; ++i) S[i] = -1, num[i] = 0;
    	for(int i = from[p]; i; i = nxt[i]) {
    		int v = to[i]; if(vis[v]) continue;
    		Size = siz[v], doit(v);
    	}
    }
    
    int main () {
    	read(n), read(m), read(k);
    	for(int i = 1, u, v, w; i <= m; ++i) {
    		read(u), read(v), read(w);
    		G[u].push_back((pii){v, w});
    		G[v].push_back((pii){u, w});
    	}
    	for(int i = 1; i <= n; ++i) sort(G[i].begin(), G[i].end());
    	dijk(1), memset(vis, 0, sizeof vis), init(1);
    	Size = n, memset(vis, 0, sizeof vis);
    	memset(dist, 0, sizeof dist), doit(1);
    	printf("%d %d
    ", MX, tot);
    	return 0;
    } 
    
  • 相关阅读:
    用户交互语句
    基础数据类型补充与总结
    Python 中表示 False 的方法
    集合
    字典
    元组
    列表
    整型数据详述和进制转换
    f-strings 详解
    字符串方法详解
  • 原文地址:https://www.cnblogs.com/water-mi/p/10280504.html
Copyright © 2020-2023  润新知