POJ-1988Cube Stacking/HDU-2818Building Block;

Cube Stacking
Time Limit: 2000MS Memory Limit: 30000K
Total Submissions: 23283 Accepted: 8166
Case Time Limit: 1000MS
->Link<-

   poj的一道题,同时也是HDu上的原题;

Building Block

                                                                                                          Time Limit: 2000/1000 MS (Java/Others)     

                                                                                                        Memory Limit: 32768/32768 K (Java/Others)
                                                                                                                             
 ->  Link  <-     

   题目还不错,带权值并查集;

  题意:有N个木块初始都放在第一层,对木块有两种操作,一种是将编号为X的木块所在的这一整列木块放在编号为Y的木块所在的这列木块上方;一种是查询编号为X的木块的下方有多少木块;理解样例就明白了;

  思路:本质上还是并查集,理解了并查集的原理就不难了;可以开两个数组low[]和high[],,一个记录某个木块上方有多少木块,一个记录这个木块到离他最近的父亲节点的木块个数(这里“最近的父亲节点”正是并查集的原理);在移动某个木块的时候实际上是移动它所在的这一整列木块,然后更新的时候只需将X的父亲节点的父亲节点改成Y的父亲节点,将Y的所在的这一列的木块个数赋给X的父亲节点的一个数组,将Y所在的这一整列木块个数加上X所在的这一整列木块个数;查询的时候利用find()函数递归查找;

const int N=30000+10;
int f[N],h[N],low[N],m;
int find(int x)
{
    if(f[x]==-1)
        return x;
    int dx=find(f[x]);
    low[x]+=low[f[x]];
    return f[x]=dx;
}
int main()
{
    scanf("%d",&m);
    memset(low,0,sizeof(low));
    memset(f,-1,sizeof(f));
    for(int i=1; i<N; i++)
        h[i]=1;
    while(m--)
    {
        char c;
        int x,y;
        getchar();
        scanf("%c",&c);
        if(c=='M')
        {
            scanf("%d%d",&x,&y);
            int xx=find(x);
            int yy=find(y);
            if(xx==yy)//如果两个木块已经在同一列就不用操作了;
                continue;
            f[xx]=yy;
            low[xx]=h[yy];
            h[yy]+=h[xx];
        }
        else
        {
            scanf("%d",&x);
            find(x);
            printf("%d\n",low[x]);
        }
    }
    return 0;
}
也可以用结构体来记录两个变量;
const int N=30000+10;
struct node
{
    int h,low;
} a[N];
int f[N],m;
int find(int x)
{
    if(f[x]==-1)
        return x;
        int dx=find(f[x]);
    a[x].low+=a[f[x]].low;
    return f[x]=dx;
}
int main()
{
    scanf("%d",&m);
    char c;
    int x,y;
    memset(a,0,sizeof(a));
    memset(f,-1,sizeof(f));
    for(int i=0; i<=N; i++)//HDU上的数据有0的点,所以从0开始,不然就WA;
        a[i].h=1;
    while(m--)
    {
        getchar();
        scanf("%c",&c);
        if(c=='C')
        {
            scanf("%d",&x);
           find(x);
           printf("%d\n",a[x].low);
        }
        else
        {
            scanf("%d%d",&x,&y);
            int xx=find(x);
            int yy=find(y);
            if(xx!=yy)
            {
                f[xx]=yy;
            a[xx].low=a[yy].h;
            a[yy].h+=a[xx].h;
            }
        }
    }
    return 0;
}

                 

转载于:https://www.cnblogs.com/nyist-TC-LYQ/p/7208217.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值