HEOI2016D1T1/BZOJ4551

这两天在看大纲讲的计算几何,表示懵… 然后LTY大神就给我看了D1T2(BZOJ4552,一会补),A掉后我就去看了T1,两种做法
第一种:链剖 表示并不会
第二种:并查集
自认为并查集学的可以,就开始乱搞,我大概思路是 离线,先把所有操作读入,倒序处理,如果是标记操作 ,那么将这个节点的sum–;如果是查询操作,那么去找他的父亲,看他父亲的sum是否等于0,若等于0,那么我就去合并连通块,将当前的父亲的父亲赋值给读入的关系,并重复上述操作,知道找到sum不为0的祖先,这就是本次查找出的答案,把它记录在ans数组里,因为我们是倒序处理的,要注意输出的顺序。

直接放代码

/**************************************************************
    Problem: 4551
    User: wbxdhr
    Language: C++
    Result: Accepted
    Time:1012 ms
    Memory:3672 kb
****************************************************************/

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int dit[100010],rel[100010],sum[100010],fa[100010],qu[100010],ans[100010];
int find(int x)
{
    if(fa[x]==x)
    {
        return x;
    }
    else
    {
        fa[x]=find(fa[x]);
        return fa[x];
    }
}
int main()
{
    int n,m,i,a,b,fz,faa,cnt=0;
    char s[5];
    sum[1]=1000001;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&a,&b);
        rel[b]=a;
    }
    for(i=1;i<=m;i++)
    {
        scanf("%s%d",s,&a);
        dit[i]=a;
        if(s[0]=='C')//change
        {
            qu[i]=1;
            sum[a]++;
        }
        else//find
        {
            qu[i]=2;
        }
    }
    for(i=0;i<=100009;i++)
    {
        fa[i]=i;
    }
    for(i=m;i>=1;i--)
    {
        if(qu[i]==1)//change
        {
            sum[dit[i]]--;
            if(sum[dit[i]]==0)
            {
                fa[dit[i]]=rel[dit[i]];
            }
        }
        else//find
        {
            fz=dit[i];
            while(1)
            {
                faa=find(fz);
                if(sum[faa]==0)
                {
                    fa[faa]=rel[faa];
                }
                else
                {
                    break;
                }
            }
            cnt++;
            ans[cnt]=faa;
        }
    }
    for(i=cnt;i>=1;i--)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}

重新贴一份代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int fa[100010],rel[100010],p[100010],num[100010],ans[100010];
bool chg[100010];
int find(int x){
    if(fa[x]==x)    return x;
    else{
        fa[x]=find(fa[x]);
        return fa[x];
    }
}
int main()
{
    int n,i,q,a,b,cnt=1,faa;    char c[5];
    scanf("%d%d",&n,&q);
    for(i=1;i<n;i++){
        scanf("%d%d",&a,&b);
        rel[b]=a;
    }
    for(i=1;i<=q;i++){
        scanf("%s%d",c,&p[i]);
        if(c[0]=='C'){
            chg[i]=true;
            num[p[i]]++;
        }
        else    chg[i]=false;
    }
    num[1]+=1000000;
    for(i=0;i<=n;i++)   fa[i]=i;
    for(i=q;i>=1;i--)
    {
        if(chg[i]==true)
        {
            num[p[i]]--;
            if(num[p[i]]<=0)    fa[p[i]]=rel[p[i]];
        }
        else
        {
            while(1)
            {
                faa=find(p[i]);
                if(num[faa]<=0) fa[faa]=rel[faa];
                else    break;
            }
            ans[cnt++]=faa;
        }
    }
    for(i=cnt-1;i>=1;i--)   printf("%d\n",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值