HDU 6109 数据分割(并查集+set+在线倍增法)

256 篇文章 0 订阅
38 篇文章 0 订阅

Description

w 来到百度之星的赛场上,准备开始实现一个程序自动分析系统。

这个程序接受一些形如xi=xj xixj 的相等/不等约束条件作为输入,判定是否可以通过给每个 w 赋适当的值,来满足这些条件。

输入包含多组数据。
然而粗心的小w不幸地把每组数据之间的分隔符删掉了。
他只知道每组数据都是不可满足的,且若把每组数据的最后一个约束条件去掉,则该组数据是可满足的。

请帮助他恢复这些分隔符。

Input

1 行:一个数字L,表示后面输入的总行数。

之后L行,每行包含三个整数, i,j,e ,描述一个相等/不等的约束条件,若 e=1 ,则该约束条件为 xi=xj ,若 e=0 ,则该约束条件为 xixj

i,j,L100000

xi,xjL

Output

输出共 T+1 行。

第一行一个整数 T ,表示数据组数。

接下来T行的第 i 行,一个整数,表示第i组数据中的约束条件个数。

Sample Input

6
2 2 1
2 2 1
1 1 1
3 1 1
1 3 1
1 3 0

Sample Output

1
6

Solution1

用并查集维护相等关系,用 set 维护不相等关系

x=y 时,看 x set里是否有 y ,如果有说明与之前的限制矛盾,当前这个限制是一组数据末尾,否则在并查集中合并x y ,假设将x合并到 y 中,则之前x set 中与 x 不同的数z y 也不同,故把z y 分别加入到对方的set中表示这两个数不同,并把 z x set 中删去

xy 时,看并查集中 x y是否属于同一个集合,属于则矛盾,当前这个限制是一组数据末尾,否则把 x y 分别加入到对方的 set 中表示这两个数不同

Code1

#include<cstdio>
#include<set>
#include<vector>
using namespace std;
namespace fastIO 
{
    #define BUF_SIZE 100000
    //fread -> read
    bool IOerror=0;
    inline char nc() 
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if(p1==pend) 
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if(pend==p1) 
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) 
    {
        return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x) 
    {
        char ch;
        while(blank(ch=nc()));
        if(IOerror)return;
        for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0');
    }
    #undef BUF_SIZE
};
using namespace fastIO;
#define maxn 100005
int fa[maxn];
int find(int x)
{
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}
set<int>s[maxn],ss;
set<int>::iterator it;
void init()
{
    for(it=ss.begin();it!=ss.end();it++)
        fa[*it]=*it,s[*it].clear();
    ss.clear();
}
vector<int>ans;
int main()
{
    for(int i=1;i<=100000;i++)fa[i]=i;
    int L,x,y,e,num=0;
    read(L);
    //scanf("%d",&L);
    while(L--)
    {
        num++;
        read(x),read(y),read(e);
        //scanf("%d%d%d",&x,&y,&e);
        x=find(x),y=find(y);
        ss.insert(x),ss.insert(y);
        if(e)
        {
            if(x==y)continue;
            if(s[x].find(y)!=s[x].end())
            {
                ans.push_back(num);
                num=0;
                init();
            }
            else
            {
                for(it=s[x].begin();it!=s[x].end();it++)
                {
                    s[y].insert(*it);
                    s[*it].insert(y);
                    s[*it].erase(x);
                }
                fa[x]=y;
            }
        }
        else
        {
            if(x!=y)
            {
                s[x].insert(y);
                s[y].insert(x);
            }
            else 
            {
                ans.push_back(num);
                num=0;
                init();
            }   
        }
    }
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++)printf("%d\n",ans[i]);
    return 0;
}

Solution2

并查集维护相等关系,倍增求每组数据的长度,先把限制中相等关系的用并查集合并,之后判断不相等关系是否在同一集合中

Code2

#include<cstdio>
#include<set>
#include<vector>
using namespace std;
namespace fastIO 
{
    #define BUF_SIZE 100000
    //fread -> read
    bool IOerror=0;
    inline char nc() 
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if(p1==pend) 
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if(pend==p1) 
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) 
    {
        return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x) 
    {
        char ch;
        while(blank(ch=nc()));
        if(IOerror)return;
        for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0');
    }
    #undef BUF_SIZE
};
using namespace fastIO;
#define maxn 100005
int n,x[maxn],y[maxn],e[maxn],fa[maxn];
int find(int x)
{
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}
int unite(int x,int y)
{
    x=find(x),y=find(y);
    if(x!=y)fa[x]=y;
}
bool check(int l,int r)
{
    if(r>n)return 0;
    for(int i=l;i<=r;i++)
        if(e[i])unite(x[i],y[i]);
    for(int i=l;i<=r;i++)
        if(!e[i]&&(find(x[i])==find(y[i])))
        {
            for(int j=l;j<=r;j++)fa[x[j]]=x[j],fa[y[j]]=y[j];
            return 0;
        }
    return 1;
}
vector<int>ans;
int main()
{
    read(n);
    //scanf("%d",&n);
    for(int i=0;i<=n;i++)fa[i]=i;
    for(int i=1;i<=n;i++)read(x[i]),read(y[i]),read(e[i]);//scanf("%d%d%d",&x[i],&y[i],&e[i]);
    for(int i=1;i<=n;)
    {
        int j=i,d=1;
        while(check(i,j+d))
        {
            while(check(i,j+2*d))d<<=1;
            j+=d;
            d=1;
        }
        if(j+d<=n)ans.push_back(j+d-i+1);
        i=j+d+1;
    }
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++)printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值