• [UOJ #393]【NOI2018】归程


    题目大意:有一张$n$个点$m$条边的图,每个边有两个属性$a_i,b_i$。有$Q$个询问,每个询问给出$v,p$,表示所有边中$b_ileqslant p$的边会被标记,在点$v$,可以通过不被标记的边到达任意点,然后用最小的$sum a_i$到达点$1$,输出这个最小值。多组数据

    $nleqslant2 imes10^5,mleqslant4 imes10^5$,最多$3$组数据。

    题解:$mathrm{kruskal}$重构树,按$b_i$从大到小建重构树,可以发现若一个点没有被标记,它的子树内均不被标记,所以可以由点$1$跑最短路,然后记录每个节点的子树内最近的值。注意,$mathrm{SPFA}$已死,要用$mathrm{dijkstra}$。

    卡点:多组数据中清空错误

    C++ Code:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    const int maxn = 6e5 + 10;
    
    int Tim, n, m, N, Q, K, S, f[maxn], w[maxn];
    int _u[maxn], _v[maxn], _l[maxn], _a[maxn], rnk[maxn];
    inline bool cmp(int a, int b) { return _a[a] > _a[b]; }
    int find(int x) { return x == f[x] ? x : (f[x] = find(f[x])); }
    long long dis[maxn];
    
    namespace Graph {
    	int head[maxn], cnt;
    	struct Edge {
    		int to, nxt, w;
    	} e[maxn << 1];
    	void addedge(int a, int b, int c) {
    		e[++cnt] = (Edge) { b, head[a], c }; head[a] = cnt;
    		e[++cnt] = (Edge) { a, head[b], c }; head[b] = cnt;
    	}
    	void clear() { memset(head, 0, sizeof head), cnt = 0; }
    
    	int V[maxn << 2];
    	inline int getmin(int a, int b) { return dis[a] < dis[b] ? a : b; }
    	void modify(int rt, int l, int r, int p, int v) {
    		if (l == r) { V[rt] = v; return ; }
    		int mid = l + r >> 1;
    		if (p <= mid) modify(rt << 1, l, mid, p, v);
    		else modify(rt << 1 | 1, mid + 1, r, p, v);
    		V[rt] = getmin(V[rt << 1], V[rt << 1 | 1]);
    	}
    
    	void dijkstra(int S) {
    		memset(dis, 0x3f, sizeof dis), memset(V, 0, sizeof V);
    		dis[S] = 0, modify(1, 1, n, S, S);
    		for (int Tim = n; Tim; --Tim) {
    			int u = V[1]; modify(1, 1, n, u, 0);
    			for (int i = head[u], v; i; i = e[i].nxt) {
    				v = e[i].to;
    				if (dis[v] > dis[u] + e[i].w)
    					dis[v] = dis[u] + e[i].w, modify(1, 1, n, v, v);
    			}
    		}
    	}
    }
    
    const int M = 24;
    int fa[maxn][M + 1];
    void addedge(int a, int b) {
    	fa[b][0] = a, dis[a] = std::min(dis[a], dis[b]);
    }
    long long query(int v, int p) {
    	for (int i = M; ~i; --i) if (w[fa[v][i]] > p) v = fa[v][i];
    	return dis[v];
    }
    
    int main() {
    	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    	std::cin >> Tim;
    	while (Tim --> 0) {
    		Graph::clear(), w[0] = -0x3f3f3f3f, memset(fa, 0, sizeof fa);
    
    		std::cin >> n >> m, N = n;
    		for (int i = 0, l; i < m; ++i) {
    			std::cin >> _u[i] >> _v[i] >> l >> _a[i];
    			Graph::addedge(_u[i], _v[i], l);
    			rnk[i] = i;
    		}
    		Graph::dijkstra(1);
    
    		for (int i = 1; i <= n + m; ++i) f[i] = i;
    		std::sort(rnk, rnk + m, cmp);
    		for (int i = 0, u, v; i < m; ++i) {
    			u = find(_u[rnk[i]]), v = find(_v[rnk[i]]);
    			if (u != v) {
    				addedge(++N, u), addedge(N, v);
    				w[N] = _a[rnk[i]], f[u] = f[v] = N;
    			}
    		}
    		for (int i = 1; i <= M; ++i)
    			for (int j = 1; j <= N; ++j)
    				fa[j][i] = fa[fa[j][i - 1]][i - 1];
    
    		std::cin >> Q >> K >> S;
    		long long v, p, ans = 0;
    		while (Q --> 0) {
    			std::cin >> v >> p;
    			if (K) v = (v + ans - 1) % n + 1,
    				p = (p + ans) % (S + 1);
    			ans = query(v, p);
    			std::cout << ans << '
    ';
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    poj1581
    poj3094
    poj2196
    poj1003
    poj2262
    poj1083
    poj3299
    poj2739
    poj1552
    js 获取元素高度和宽度
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/11628351.html
Copyright © 2020-2023  润新知