zoukankan      html  css  js  c++  java
  • 【题解】 [AHOI2013]连通图 hash+差分/线段树分治+并查集 Luogu5227

    Legend

    给定一个无向连通图和若干个小集合,每个小集合包含一些边,对于每个集合,你需要确定将集合中的边删掉后改图是否保持联通。集合间的询问相互独立

    定义一个图为联通的当且仅当对于任意的两个顶点,都存在一条路径连接它们。

    点数 (1 le n le 10^5),集合数量 (1 le k le 10^5),边数量 (1 le m le 2 imes 10^5),集合大小 (1 le c le 4)

    Editorial

    一眼线段树分治对吧,但是这么做是非常没有意思的。

    考虑直接 ( m{dfs}) 建立一棵生成树,剩下的都是返祖边,不妨看成一次覆盖操作。

    这棵树有以下性质:

    • 仅割掉返祖边图一定联通。
    • 一条树边割掉之后,必须要把所有覆盖了它的返祖边割掉才能使得图不联通。

    所以我们把每一条返祖边设定一个随机 hash 值,把每一条树边 hash 值设置成所有覆盖了它的返祖边的 hash 异或和。

    这样每次查询只需要看是否存在一个包含返祖边的子集 hash 值异或和为 (0)

    每次查询的错误概率为:( extrm{unsigned int}) 范围选出 (c) 个整数,存在一个子集异或为 (0) 的概率。这个东西我显然是不会算的。

    复杂度 (O(malpha(n)+2^ck))

    Code

    代码实现的时候我很懒,没有检查集合是否有返祖先边。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int read(){
    	char k = getchar(); int x = 0;
    	while(k < '0' || k > '9') k = getchar();
    	while(k >= '0' && k <= '9')
    		x = x * 10 + k - '0' ,k = getchar();
    	return x;
    }
    
    const int MX = 2e5 + 233;
    
    int head[MX] ,tot = 1;
    struct edge{
    	int node ,next ,w;
    }h[MX << 1];
    void addedge(int u ,int v ,int w ,int flg = 1){
    	h[++tot] = (edge){v ,head[u] ,w} ,head[u] = tot;
    	if(flg) addedge(v ,u ,w ,false);
    }
    
    struct E{
    	int u ,v ,w;
    }e[MX];
    
    int vis[MX] ,cnt ,dis[MX];
    void dfs(int x ,int f = 0){
    	vis[x] = ++cnt;
    	for(int i = head[x] ,d ; i ; i = h[i].next){
    		d = h[i].node;
    		if(d == f) continue;
    		if(vis[d]){
    			if(vis[d] < vis[x]){
    				dis[d] ^= h[i].w;
    				dis[x] ^= h[i].w;
    			}
    		}else{
    			dfs(d ,x);
    			dis[x] ^= dis[d];
    			e[i / 2].w = dis[d];
    		}
    	}
    }
    
    int main(){
    	int n = read() ,m = read();
    	for(int i = 1 ; i <= m ; ++i){
    		e[i].u = read() ,e[i].v = read();
    		e[i].w = 1u * i * i + 1u * rand();
    		addedge(e[i].u ,e[i].v ,e[i].w);
    	}
    	dfs(1);
    	int k = read();
    	while(k--){
    		int s = read();
    		int a[4];
    		for(int i = 0 ; i < s ; ++i) a[i] = read();
    		int ok = 0;
    		for(int i = 1 ; i < 1 << s && !ok ; ++i){
    			int v = 0;
    			for(int j = 0 ; j < s ; ++j){
    				if((i >> j) & 1) v ^= e[a[j]].w;
    			}
    			if(v == 0) ok = true;
    		}
    		printf("%sonnected
    " ,ok ? "Disc" : "C");
    	}
    	return 0;
    }
    
  • 相关阅读:
    《ASP.NET Core跨平台开发从入门到实战》Web API自定义格式化protobuf
    .NET Core中文分词组件jieba.NET Core
    .NET Core 2.0及.NET Standard 2.0
    Visual Studio 2017 通过SSH 调试Linux 上.NET Core
    Visual Studio 2017 ASP.NET Core开发
    Visual Studio 2017正式版离线安装及介绍
    在.NET Core 上运行的 WordPress
    IT人员如何开好站立会议
    puppeteer(二)操作实例——新Web自动化工具更轻巧更简单
    puppeteer(一)环境搭建——新Web自动化工具(同selenium)
  • 原文地址:https://www.cnblogs.com/imakf/p/13688027.html
Copyright © 2011-2022 走看看