zoukankan      html  css  js  c++  java
  • AGC002

    D - Stamp Rally

    • 题意:给定(n<=100 000)个点的无向图,有(m<=100 000)条边,输入(m)条边,第(i)条边,边权是(i),有(q <= 100 000)个询问,每个询问给出两个点(x)(y),和数量(z),求从(x)点和(y)点出发,任意恰好走(z)条边,求经过的最大边权最小是多少。
    • 题解:用了黑科技克鲁斯卡尔重构树,好像用可持久化并查集和整体二分也能过,因为感觉克鲁斯卡尔重构树较为容易掌握,就先学了这个。克鲁斯卡尔重构树就是在克鲁斯卡尔最小生成树上,按边权从小到大的顺序,新增(n-1)个点,将每条边的两个端点的父亲节点连向新增的点,新增的点权即为边权。
    • 代码:
    #include <iostream>
    #include <vector>
    using namespace std;
    const int N = 1e6 + 9;
    const int inf = 0x3f3f3f3f;
    vector<int>G[N];
    int f[N];
    int Find(int x) {return f[x] == x?x:f[x] = Find(f[x]);}
    int V[N];
    int sz[N];
    int fa[N][20];
    void dfs(int u, int father) {
    	fa[u][0] = father;
    	for (int i = 1; i <= 17; i++) {
    		fa[u][i] = fa[fa[u][i-1]][i-1];
    	}
    	for (auto v : G[u]) {
    		if (father == v)continue;
    		dfs(v, u);
    		sz[u] += sz[v];
    	}
    	if (sz[u] == 0)sz[u]++;
    	return ;
    }
    bool check(int x, int y, int mid, int cnt) {
    	for (int i = 17; i >= 0; i--) {
    		if (V[fa[x][i]] <= mid)x = fa[x][i];
    		if (V[fa[y][i]] <= mid)y = fa[y][i];
    	}
    	int t = 0;
    	if (x == y) t = sz[x];
    	else t = sz[x] + sz[y];
    	if (t < cnt)return 1;
    	else return 0;
    }
    int main() {
    	int n, m;
    	ios::sync_with_stdio(0);
    	cin >> n >> m;
    	for (int i = 1; i <= n + n; i++)f[i] = i;
    	int cnt = 0;
    	V[0] = inf;
    	for (int i = 1;  i <= m; i++) {
    		int u, v, w;
    		cin >> u >> v;
    		int fx = Find(u);
    		int fy = Find(v);
    		if (fx != fy && cnt <= n-1){
    			cnt++;
    			int node = n + cnt;
    			V[node] = i;
    			G[node].push_back(fx);
    			G[node].push_back(fy);
    			f[fx] = node;
    			f[fy] = node;
    		}
    	}
    	dfs(n + cnt, 0);
    	int q;
    	cin >> q;
    	while (q--) {
    		int u, v, z;
    		cin >> u >> v >> z;
    		int l = 0, r = n* 2;
    		int ans;
    		while (l < r) {
    			int mid = l + r >> 1;			
    			if (check(u, v, mid, z)) {
    				l = mid + 1;
    			} else {
    				ans = r;r = mid;
    			}
    		}
    		cout << l << endl;
    	}
    }
    
  • 相关阅读:
    js 获取两个日期相差的天数--自定义方法
    C# Dictionary类型转json方法之一
    C# Obsolete(已弃用方法属性)
    css 样式计算器
    edge 浏览器自动识别电话号码解问题解决方法
    js 中止程序继续进行(break continue return throw)
    js根据等号(=)前名称获取参数值
    JS 时间格式为/Date(1332919782070)/ 转化为正常的格式
    input 内容发生改变时触发事件
    自我介绍for软件工程课程
  • 原文地址:https://www.cnblogs.com/Xiao-yan/p/14339128.html
Copyright © 2011-2022 走看看