• [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;
    }
    
  • 相关阅读:
    主效应|处理误差 |组间误差|处理效应|随机误差|组内误差|误差|效应分析|方差齐性检验|SSE|SSA|SST|MSE|MSA|F检验|关系系数|完全随机化设计|区组设计|析因分析
    第二类错误|检验统计量|左偏|右偏|P值
    估计量|估计值|置信度|置信水平|非正态的小样本|t分布|大样本抽样分布|总体方差|
    参数|统计量|抽样分布|估计标准误差|标准误差|标准误|标准差|二项分布|泊松分布|中心极限定理|样本方差|
    ruby 分析日志,提取特定记录
    find 找出大文件
    momentjs 求小时差异
    linux下对date和timestamp的互转
    golang protobuf SetExtension
    对文本中的某两列求和,请统计重复出现次数
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/13394035.html
Copyright © 2020-2023  润新知