hdu6109

来源:互联网 发布:python量化投资之路 编辑:程序博客网 时间:2024/06/03 17:03

这道题有两个关系,相等关系和不等关系,相等关系有传递性,这个很容易想到并查集这个数据结构来表示这个关系,然后是不等关系,这个因为没有传递关系,所以不能用并查集来表示。这道题一开始我想到的是挑战程序设计书上的食物链那道题,想要用unite(a,b+MAXN),unite(a+MAXN,b)来表示不等关系,这种方法是错的,这种方法是当a,b表示不在同一集合,并且集合种类只有两个的时候才是这样做法。
然后是,可以考虑用set来记录不等,当a!=b的时候,给a的set压入b,给b的set压入a,这样当询问a和某个数是否有不相等关系的时候,查一查a的set里面有没有这个数。
考虑set的方法和并查集结合起来,当a和b合在同一个集合s中的时候,如果把a的set和b的set的信息都添加到s的set里面。考虑以下这种情况,a!=c,b!=d,a==b,那么c和b是肯定不相等的,当a和b合并集合的时候,按上面说的那种想法,那么此时find(b)的set里面一查就有c这个数了,这样就能判断出c这个数不等于b了。具体的实现是在并查集的find函数里面加一个pushup函数,类似与线段树的pushup,把儿子的信息合并到父亲身上,这种时间复杂度因为并查集的路径压缩可以很小。
这种两种方法结合在一起的思想。

#include<bits/stdc++.h>#define rank rrrusing namespace std;const int MAXN = 1e5+10;int par[MAXN];set<int> ops[MAXN];int cnt;void init(){    for(int i=0;i<MAXN;i++)    {        par[i]=i;        ops[i].clear();    }    cnt=0;}void pushup(int u,int fa)//多了一个pushup函数{    for(auto x : ops[u])        ops[fa].insert(x);}int find(int x){    if(par[x]==x)        return x;    else    {        pushup(x,par[x]);        return par[x]=find(par[x]);    }}void unite(int x,int y){    x=find(x);    y=find(y);    if(x==y) return ;    if(ops[x].size()<ops[y].size())        par[x]=y;    else    {        par[y]=x;    }}bool same(int x,int y){    return find(x)==find(y);}int main(){    if (fopen("in.txt", "r") != NULL)    {        freopen("in.txt", "r", stdin);        // freopen("out.txt", "w", stdout);    }    int t;    cin>>t;    init();    queue<int> ans;    for(int i=1;i<=t;i++)    {        int a,b,c;        scanf("%d%d%d",&a,&b,&c);        a=find(a);//找ab各自的集合        b=find(b);        cnt++;        if(c)        {            if(ops[a].count(b)||ops[b].count(a))            {                ans.push(cnt);                init();            }            else            {                unite(a,b);            }        }        else        {            if(a==b)            {                ans.push(cnt);                init();            }            else            {                ops[a].insert(b);                ops[b].insert(a);            }        }    }    printf("%d\n",ans.size());    while(ans.size())    {        printf("%d\n",ans.front());        ans.pop();    }    return 0;}
原创粉丝点击