20. 军训日记:查寝

小军的军训进行到了一半了,今天军训教官搞了一波突然袭击,进行了一个寝的查。

提前了解到查寝消息的小军准备进行一波整理归纳,来使自己的寝室变得更加整洁。具体来说,小军有n件物品,放在n个盒子里,第i个盒子有物品i,小军会进行m次整理,第i次整理,小军会依次在第x个盒子顶拿走物品放入第y个盒子内,直至第x个盒子完全搬空。比如第1个盒子自顶向下有物品1、2,第2个盒子有物品3,将盒子1内的物品搬入盒子2内后结果是: 第1个盒子没有物品,第2个盒子自顶向下是2、1、3

现在,小军告诉你n还有m次操作具体是什么,你能告诉他最后每个盒子内有几个物品,他们具体是什么么?

输入:

一个正整数n代表盒子和物品数,一个正整数m代表整理归纳的次数

接下来m行输入,一行两个正整数x y,代表用上述的方法将盒子x的物品搬到盒子y里

1n≤10^5, 1≤m≤10^6, 1≤x,y≤n

题目保证x != y

输出;

有n行输出

第i行,先输出一个正整数k,表示第i个盒子内的物品数,接下来输出n个数,表示第i个盒子自顶向下的物品标号

注意:

行末无空格,文末有回车。

解题思路:

由于复杂度较高,因此我们不能模拟入栈出栈过程;考虑到每一个过程都相当于一个有序的串反向挪到另一个串的后面,因此我们可以用双链表来实现这个过程,而如何简易存储呢?我们可以定义五个数组,前两个存每一个值左右为哪个值,后两个存每一个栈第一个和最后一个元素是哪个值,中间存当前栈有多少个元素

首先进行初始化,每一个栈i开始和结束的值都为i,栈中有1个元素

每一个i左右都为0

之后进行m次移动,设将x移动到y,这里分为三种情况,第一种x元素个数为0,这种不用管,第二种是y元素个数为0,将x的开头记为y的结尾,x的结尾记为y的开头,y元素个数记为x的,x的更改为0.

第三种情况我们先将xy的尾元素连接起来,由于连接后不会再分开,因此并且最多连两次,我们可以将x左右为零的连y,y左右为零的连x,y队尾为x队头,y元素数量加上x的,x元素数量记为零

之后进行n个栈的输出

先将零的输出0

之后若有元素则输出个数,从尾部向前输出,不用管左右,如果刚刚输出过就输出另一边,这样就能保证顺序。

代码:(纯数组模拟hhhh)

#include<iostream>  
using namespace std;  
long long idx;  
int ne[100010][7];  
int hd[100010][3];  
void init(int n){  
    for(int i=1;i<=n;i++){  
        ne[i][0]=i;//存的值 
        ne[i][1]=0;//左
        ne[i][2]=0;//右  
        hd[i][0]=1;//个数  
        hd[i][1]=i;//头 
        hd[i][2]=i;//尾  
    }  
}  
int main(){  
    int n,m;  
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);  
    cin>>n>>m;  
    init(n);  
    while(m--){  
        int x,y;  
        cin>>x>>y;  
        if(hd[x][0]==0)continue;  
         if(hd[y][0]==0){  
            hd[y][0]+=hd[x][0];  
            hd[x][0]=0;  
            hd[y][1]=hd[x][2];  
            hd[y][2]=hd[x][1];  
        }  
        else {  
            if(ne[hd[y][2]][2]==0)  
            ne[hd[y][2]][2]=hd[x][2];  
            else ne[hd[y][2]][1]=hd[x][2];  
            if(ne[hd[x][2]][1]==0)  
            ne[hd[x][2]][1]=hd[y][2];  
            else ne[hd[x][2]][2]=hd[y][2];  
            hd[y][2]=hd[x][1];  
            hd[x][2]=hd[y][1];  
            hd[y][0]+=hd[x][0];  
            hd[x][0]=0;   
        }  
    }  
    for(int i=1;i<=n;i++){  
        if(hd[i][0]==0){  
            cout<<0<<endl;  
        }  
        else {  
            cout<<hd[i][0]<<' ';  
            int t=hd[i][2];  
            for(int j=hd[i][2];;){  
                  
                cout<<j;  
                if(j!=hd[i][1])cout<<' ';  
                if(j==hd[i][1]){  
                    cout<<endl;break;  
                }  
                if(j==t){  
                    if(ne[j][1]==0){  
                        t=j;  
                        j=ne[j][2];  
                    }  
                    else {  
                        t=j;  
                        j=ne[j][1];  
                    }  
                }  
                else{  
                    if(ne[j][1]==t){  
                        t=j;  
                        j=ne[j][2];  
                    }  
                    else {  
                        t=j;  
                        j=ne[j][1];  
                    }  
                }  
                  
            }  
        }  
    }  
}  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值