黑魔法师之门 (magician)-并查集

题目

经过了 16 个工作日的紧张忙碌,未来的人类终于收集到了足够的能源。然而在与 Violet 星球的战争中,由于 Z 副官的愚蠢,地球的领袖 applepi 被邪恶的黑魔法师 Vani 囚禁在了 Violet 星球。为了重启 Nescafé这一宏伟的科技工程,人类派出了一支由 XLk、Poet_shy 和 lydrainbowcat 三人组成的精英队伍,穿越时空隧道,去往 Violet 星球拯救领袖 applepi。 applepi 被囚禁的地点只有一扇门,当地人称它为“黑魔法师之门”。这扇门上画着一张无向无权图,而打开这扇门的密码就是图中每个点的度数大于零且都是偶数的子图的个数对1000000009 取模的值。此处子图 (V, E) 定义为:点集 V和边集 E 都是原图的任意子集,其中 E 中的边的端点都在V中。但是 Vani 认为这样的密码过于简单,因此门上的图是动态的。起初图中只有 N 个顶点而没有边。Vani 建造的门控系统共操作 M 次,每次往图中添加一条边。你必须在每次操作后都填写正确的密码,才能够打开黑魔法师的牢狱,去拯救伟大的领袖 applepi。

输入输出

第一行包含两个整数 N 和 M。 接下来 M 行,每行两个整数 A和 B,代表门控系统添加了一条无向边 (A, B)。

输出一共 M 行,表示每次操作后的密码。

输入样例

4 8
3 1
3 2
2 1
2 1
1 3
1 4
2 4
2 3

输出样例

0
0
1
3
7
7
15
31

题意简述:每次加边之后输出当前图满足条件的子图总个数。

解题思路:这道题,比较迷。首先我是没有想到怎么做的。但是,我发现输出有点东西。简化一下样例输出就是:0,1,3,7,15,31.大声的告诉我,你们找到规律了吗!没找到。如此明显,规律当然是依次*2+1了。可是我也发现答案也并不是这么简单,毕竟还是有加了边却没发现子图的。那么什么时候才能改变答案呢?我们不难发现,满足题意的一个显而易见子图为一个三角形。三个点,三条边。也就是说,加了边之后能构成一个三角形,就能*2+1.

那么如何判断是否为三角形?很简单,判断这条新边的端点在没加入之前是否有一个共同的连接点。于是,就有了如下的代码。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<fstream>
#include<set>
#define ll long long
using namespace std;
int read(){
    int res=0,f=1;
    char ch;
    ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘)f=-1;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘){
        res=res*10+(ch-‘0‘);
        ch=getchar();
    }
    return res*f;
}
const int MAXN=200005;
const ll mod=1000000009;
int n,m;
set<int> u[MAXN];
ll ans;
int main(){
    n=read();m=read();
    for(int i=1;i<=n;++i)u[i].insert(i);
    for(int i=1;i<=m;++i){
        int c,b;
        b=read();
        c=read();
        int fl=0;
        for(set<int>::iterator iter=u[b].begin();iter!=u[b].end();++iter){
            int p=*iter;
            if(u[c].count(p)){
                fl=1;
                break;
            }
        }
        u[b].insert(c);u[c].insert(b);
        if(fl)ans=ans*2+1;
        printf("%lld\n",ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

不过这段代码的速度与正确性都难以保证,毕竟一个环也是满足提议的,也就是说还要将能找到的更新一遍。绝对超时。

于是,就有了我们的并查集。(并查集是什么我就不写了)

运用并查集,若两端在同一集合中,就*2+1,若不在,就加入到同一集合,不改变答案。

ACcode:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<fstream>
#include<set>
#define ll long long
using namespace std;
int read(){
    int res=0,f=1;
    char ch;
    ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘)f=-1;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘){
        res=res*10+(ch-‘0‘);
        ch=getchar();
    }
    return res*f;
}
const int MAXN=200005;
const ll mod=1000000009;
int n,m;
int f[MAXN];
ll ans;
int find_f(int x){
    return x==f[x]?x:f[x]=find_f(f[x]);
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;++i)f[i]=i;
    for(int i=1;i<=m;++i){
        int c,b;
        b=read();
        c=read();
        int q=find_f(b),p=find_f(c);
        if(q!=p){
            f[q]=c;
        }
        else ans=(ans*2+1)%mod;
        printf("%lld\n",ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

不过,笔者我到现在也不太能够证明这个方法的正确性。我唯一能想到的解释就是,若在同一集合,则必然找的到一条路径使得两端点联通,此时这条路径与新加入的边是等价的。那么此时新加入的边与路径构成一个只有两个点的圆,是一个全新的子图,这是+1.而新加入的边同时也可以代替那一条路径,使得原来的方案双倍。这是*2.




原文地址:https://www.cnblogs.com/clockwhite/p/11259945.html

时间: 2024-08-07 01:30:58

黑魔法师之门 (magician)-并查集的相关文章

[codevs 1995]黑魔法师之门(并查集)

题目:http://codevs.cn/problem/1995/ 分析:脑补一下满足题目要求的子图肯定就是环……于是题目就变成了不断加边求环的个数.看起来有点麻烦……但是环的实质是几个小环组合起来的……所以我们只需要知道最基础的环的个数就行了,根据二项式定理那么就是2^(最基础的环的个数)-1.还是不好做啊!!!!!! 没关系……并查集来了…… 假设对于第i-1操作后,最终答案为ans,那么对于第i次操作,分为两种情况 ①加入这条边后,没有出现新环,那么说明对结果无影响,结果还是ans ②加入

黑魔法师之门

并查集 黑魔法师之门 试题描述   经过了16 个工作日的紧张忙碌,未来的人类终于收集到了足够的能源.然而在与Violet星球的战争中,由于Z 副官的愚蠢,地球的领袖applepi 被邪恶的黑魔法师Vani 囚禁在了Violet 星球.为了重启Nescafé这一宏伟的科技工程,人类派出了一支由XLk.Poet_shy 和lydrainbowcat 三人组成的精英队伍,穿越时空隧道,去往Violet 星球拯救领袖applepi.applepi 被囚禁的地点只有一扇门,当地人称它为“黑魔法师之门”.

CODEVS1995 || TYVJ1863 黑魔法师之门

P1863 [Poetize I]黑魔法师之门 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 经过了16个工作日的紧张忙碌,未来的人类终于收集到了足够的能源.然而在与Violet星球的战争中,由于Z副官的愚蠢,地球的领袖applepi被邪恶的黑魔法师Vani囚禁在了Violet星球.为了重启Nescafé这一宏伟的科技工程,人类派出了一支由XLk.Poet_shy和lydrainbowcat三人组成的精英队伍,穿越时空隧道,去往Violet星球拯救领袖

刷过一题之黑魔法师之门

经过了16 个工作日的紧张忙碌,未来的人类终于收集到了足够的能源.然而在与Violet星球的战争中,由于Z 副官的愚蠢,地球的领袖applepi 被邪恶的黑魔法师Vani 囚禁在了Violet 星球.为了重启Nescafé这一宏伟的科技工程,人类派出了一支由XLk.Poet_shy 和lydrainbowcat 三人组成的精英队伍,穿越时空隧道,去往Violet 星球拯救领袖applepi.applepi 被囚禁的地点只有一扇门,当地人称它为“黑魔法师之门”.这扇门上画着一张无向无权图,而打开这

入门OJ 4192: [Noip模拟题]黑魔法师之门

题目 Description applepi被囚禁的地点只有一扇门,当地人称它为"黑魔法师之门".这扇门上画着一张无向无权图,而打开这扇门的密码就是图中[每个点的度数大于零且都是偶数]的子图的个数对1000000009取模的值.此处子图 (V, E) 定义为:点集V和边集E都是原图的任意子集,其中E中的边的端点都在V中.但是Vani认为这样的密码过于简单,因此门上的图是动态的.起初图中只有N个顶点而没有边.Vani建造的门控系统共操作M次,每次往图中添加一条边.你必须在每次操作后都填写

[Poetize I]黑魔法师之门

描述 Description applepi被囚禁的地点只有一扇门,当地 人称它为“黑魔法师之门”.这扇门上画着一张无向无权图,而打开这扇门的密码就是图中[每个点的度数大于零且都是偶数]的子图的个数对 1000000009取模的值.此处子图 (V, E) 定义为:点集V和边集E都是原图的任意子集,其中E中的边的端点都在V中. 但是Vani认为这样的密码过于简单,因此门上的图是动态的.起初图中只有N个顶点而没有边.Vani建造的门控系统共操作M次,每次往图中添加一条边.你必须在每次操作后都填写正确

2014082701黑魔法师之门(C++)

#include<iostream>#define p 1000000009using namespace std;int read() { int f=0; char x;x=getchar(); while(x<'0'||x>'9') x=getchar(); while(x>='0'&&x<='9') { f=f*10+x-'0'; x=getchar(); } return f;}int fa[200001];int find(int x){re

TYVJ并查集

神奇的并查集 P1017 冗余关系 当年刚刚学会并查集,合并写的是rank(),ce了好多次 #include <cstdio> int father[5001]; int m,n,c,d,a; int find(int a){ return (father[a]==a) ? a : (father[a]=find(father[a])); } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=m;i++

hihoCoder - 1066 - 无间道之并查集 (并查集 + map)

#1066 : 无间道之并查集 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 这天天气晴朗.阳光明媚.鸟语花香,空气中弥漫着春天的气息--额,说远了,总之,小Hi和小Ho决定趁着这朗朗春光出去玩. 但是刚刚离开居住的宾馆不久,抄近道不小心走入了一条偏僻小道的小Hi和小Ho就发现自己的前方走来了几个彪形大汉,定睛一看还都是地地道道的黑人兄弟!小Hi和小Ho这下就慌了神,捡肥皂事小,这一身百把来斤别一不小心葬身他乡可就没处说去了. 就在两人正举足无措之时,为首的黑叔叔