• [NOI2018]归程(kruscal重构树+最短路+树上倍增)


    NOI的模板题?貌似2018已经有两道模板了啊?

    我们现在想要找到一个点集,使得从起点到点集中的每个点一定存在一条路径使得这条路径上的最小边大于水位线。

    这就要使得我们从起点找到一条到每个点的路径使得路径上的最小边尽量打。这不就是kruskal重构树能干的事吗?不会的点.

    我们在重构树上倍增,找到一个深度最浅的节点使得其权值大于水位线,则其子树内的叶节点都是可以到的。

    剩下的交给步行,我们发现终点是固定的所以步行的最短路是固定的,直接spfa搞出一个最短路再树形dp统计一下就行。

    时间复杂度是(nlog{n})级别的。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <vector>
    using namespace std;
    const int N = 400010;
    const int M = 400010;
    template <typename T> void read(T &x) {
    	T ff = 1;
    	char cch = getchar();
    	for (; '0' > cch || cch > '9'; cch = getchar()) if (cch == '-') ff = -1;
    	for (x = 0; '0' <= cch && cch <= '9'; cch = getchar()) x = x * 10 + cch - '0';
    	x *= ff;
    }
    struct node{
    	int pre, to, val;
    }edge[N << 1];
    struct EDGE{
    	int u, v, l, w;
    	friend bool operator < (EDGE x, EDGE y) {
    		return x.w > y.w;
    	}
    }ed[M];
    int head[N], tot;
    int fa[N], val[N];
    int ch[N][2], dp[N], dis[N];
    bool vis[N];
    int f[N][21];
    int T;
    int n, m, cnt;
    int Q, k, s;
    int ans;
    priority_queue<pair<int, int> > q;
    void add(int u, int v, int l) {
    	edge[++tot] = node{head[u], v, l};
    	head[u] = tot;
    }
    void init() {
    	tot = 0;
    	for (int i = 1; i <= n; i++) head[i] = 0;
    }
    void dfs(int x) {
    	dp[x] = 0x3f3f3f3f;
    	if (val[x] >= 0x3f3f3f3f) dp[x] = dis[x];
    	for (int i = 1; i <= 20; i++) {
    		f[x][i] = f[f[x][i - 1]][i - 1];
    	}
    	if (ch[x][0]) {
    		f[ch[x][0]][0] = x;
    		dfs(ch[x][0]);
    		dp[x] = min(dp[x], dp[ch[x][0]]);
    	}
    	if (ch[x][1]) {
    		f[ch[x][1]][0] = x;
    		dfs(ch[x][1]);
    		dp[x] = min(dp[x], dp[ch[x][1]]);
    	}
    }
    int find(int x) {
    	return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    int main() {
    	read(T);
    	while (T--) {
    		read(n); read(m);
    		init();
    		for (int i = 1; i <= m; i++) {
    			read(ed[i].u); read(ed[i].v); read(ed[i].l); read(ed[i].w);
    			add(ed[i].u, ed[i].v, ed[i].l);
    			add(ed[i].v, ed[i].u, ed[i].l);
    		}
    		for (int i = 1; i <= n; i++) dis[i] = 0x3f3f3f3f, vis[i] = 0;
    		dis[1] = 0;
    		q.push(make_pair(-dis[1], 1));
    		while (!q.empty()) {
    			int x = q.top().second;
    			q.pop();
    			if (vis[x]) continue;
    			vis[x] = 1;
    			for (int i = head[x]; i; i = edge[i].pre) {
    				int y = edge[i].to;
    				if (dis[y] > dis[x] + edge[i].val) {
    					dis[y] = dis[x] + edge[i].val;
    					q.push(make_pair(-dis[y], y));
    				}
    			}
    		}
    		int limit = (n << 1) - 1;
    		cnt = n;
    		for (int i = 1; i <= limit; i++) fa[i] = i;
    		sort(ed + 1, ed + 1 + m);
    		for (int i = 1; i <= n; i++) val[i] = 0x3f3f3f3f, ch[i][0] = ch[i][1] = 0;
    		for (int i = 1; i <= m; i++) {
    			int x = ed[i].u, y = ed[i].v;
    			int fx = find(x), fy = find(y);
    			if (fx != fy) {
    				cnt++;
    				val[cnt] = ed[i].w;
    				fa[fx] = cnt;
    				fa[fy] = cnt;
    				ch[cnt][0] = fx;
    				ch[cnt][1] = fy;
    				if (cnt >= limit) break;
    			}
    		}
    		f[cnt][0] = 0;
    		dfs(cnt);
    		read(Q); read(k); read(s);
    		ans = 0;
    		for (int t = 1; t <= Q; t++) {
    			int v, p;
    			read(v); read(p);
    			v = (v + k * ans - 1) % n + 1;
    			p = (p + k * ans) % (s + 1);
    			for (int i = 20; i >= 0; i--) {
    				if (val[f[v][i]] > p) v = f[v][i];
    			}
    			printf("%d
    ", ans = dp[v]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    2017年0406------如何使用sessionStroage来储存参数是对象的,以及localStorage和sessionStorage的不同地方
    json格式和对象类型的转换20170330
    严重报错: Error configuring application listener of class org.springframework.web.context.ContextLoaderLis
    201703-28工作笔记:复杂的背景问题
    @Inject
    @Controller
    Mybatis
    Mybatis P2 总结
    小结--limit注入
    小结--order by 注入
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/13394035.html
Copyright © 2020-2023  润新知