zoukankan      html  css  js  c++  java
  • Codeforces Gym 101194G Pandaria (2016 ACM-ICPC EC-Final G题, 并查集 + 线段树合并)

    题目链接  2016 ACM-ICPC EC-Final Problem G

    题意  给定一个无向图。每个点有一种颜色。

       现在给定$q$个询问,每次询问$x$和$w$,求所有能通过边权值不超过$w$的边走到$x$的点的集合中,哪一种颜色的点出现的次数最多。

       次数相同时输出编号最小的那个颜色。强制在线。

     

    求哪种颜色可以用线段树合并搞定。

    关键是这个强制在线。

    当每次询问的时候,我们先要求出最小生成树在哪个时刻恰好把边权值不超过$w$的边都用并查集合并了。

    在做最小生成树的时候每合并两个节点,另外开一个新的结点,原来两个点的父亲都指向这个新的结点。

    然后倍增预处理,用类似求$LCA$的方法来得到询问的那个时刻。

    时间复杂度$O(nlogn)$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    const int N = 2e5 + 10;
    const int M = N * 20;
    
    struct node{
    	int x, y, z;
    	void scan(){
    		scanf("%d%d%d", &x, &y, &z);
    	}
    	friend bool operator < (const node &a, const node &b){
    		return a.z < b.z;
    	}
    } e[N];
    
    int T, ca = 0;
    int tot;
    int n, m, q, ans;
    int c[N], root[N], v[N], father[N];
    int ls[M], rs[M], mx[M], ret[M];
    int id, res[N];
    int f[N][19];
    
    
    int getfather(int x){
    	return father[x] == x ? x : father[x] = getfather(father[x]);
    }
    
    void up(int i){
    	mx[i] = max(mx[ls[i]], mx[rs[i]]);
    	if (mx[i] == mx[ls[i]]) ret[i] = ret[ls[i]];
    	else ret[i] = ret[rs[i]];
    }
    
    int build(int l, int r, int val){
    	int x = ++tot;
    	ls[x] = rs[x] = mx[x] = ret[x] = 0;
    	if (l == r){
    		mx[x] = 1;
    		ret[x] = val;
    		return x;
    	}
    
    	int mid = (l + r) >> 1;
    	if (val <= mid) ls[x] = build(l, mid, val);
    	else rs[x] = build(mid + 1, r, val);
    	up(x);
    	return x;
    }
    
    int Merge(int x, int y, int l, int r){
    	if (x == 0 || y == 0) return x + y;
    	if (l == r){
    		mx[x] += mx[y];
    		return x;
    	}
    
    	int mid = (l + r) >> 1;
    	ls[x] = Merge(ls[x], ls[y], l, mid);
    	rs[x] = Merge(rs[x], rs[y], mid + 1, r);
    	up(x);
    	return x;
    }
    
    int main(){
    
    	scanf("%d", &T);
    	while (T--){
    		tot = 0;
    		scanf("%d%d", &n, &m);
    		rep(i, 1, n) scanf("%d", c + i);
    
    		rep(i, 1, n){
    			father[i] = i;
    			v[i] = 0;
    			f[i][0] = i;
    			root[i] = build(1, n, c[i]);
    			res[i] = ret[root[i]];
    		}
    
    		id = n;
    		rep(i, 1, m) e[i].scan();
    
    		sort(e + 1, e + m + 1);
    
    		rep(i, 1, m){
    			int x  = e[i].x, y = e[i].y, z = e[i].z;
    			int fx = getfather(x), fy = getfather(y);
    			if (fx ^ fy){
    				++id;
    				f[id][0] = id;
    				father[id] = id;
    				v[id] = z;
    				father[fx] = father[fy] = id;
    				f[fx][0] = f[fy][0] = id;
    				root[id] = Merge(root[fx], root[fy], 1, n);
    				res[id] = ret[root[id]];
    			}
    		}
    
    
    		rep(j, 1, 17){
    			rep(i, 1, id) f[i][j] = f[f[i][j - 1]][j - 1];
    		}
    
    		printf("Case #%d:
    ", ++ca);
    		scanf("%d", &q);
    		ans = 0;
    		while (q--){
    			int x, w;
    			scanf("%d%d", &x, &w);
    			x ^= ans, w ^= ans;
    			dec(i, 17, 0) if (v[f[x][i]] <= w) x = f[x][i];
    			printf("%d
    ", ans = res[x]);
    		}
    	}
    
    	return 0;
    }
    

      

        

  • 相关阅读:
    bootstrap插件学习-bootstrap.tooltip.js
    1,2,3维数组去重方法
    使用PHP静态变量当缓存的方法
    深思 PHP 数组遍历的差异(array_diff 的实现)
    ecshop学习五
    ecshop学习四
    ecshop学习三
    ecshop学习二
    ecshop学习一
    linux下安装ecshop
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/8503505.html
Copyright © 2011-2022 走看看