upc-WNJXYK and DIDIDI and monkey(并查集启发式合并)

题目描述

DIDIDI and WNJXYK are good friends. One day, they go to the zoo. The monkeys are playing happily. There are n monkeys named 1-n. At first, the first one hangs its tail on the tree. The other n-1 monkeys, either are caught by other monkeys, or catch other monkeys, or both. In the next m seconds, every second, there will be a monkey releasing its left hand or right hand. And then some monkeys will drop on the floor. Given the relationship between monkeys, calculate the landing time of every monkey.

输入

The first line of input contains a positive integer T, telling you there are T test cases followed.
Each test case, first line includes two integers n, m. n means number of monkeys, and m as mentioned in the description.
Then following n lines, the k-th line has two integers, describe the k-th monkey’s information. The first integer is the index of monkey in its left hand, the second integer is the index of monkey in its right hand. -1 indicates there is nothing in its hand.
Then following m lines, the i-th line gives the information at time i-1, every line has two numbers, the first is the index of the monkey, the second is the hand that it releases, 1 is left hand, 2 is right hand.
It’s guaranteed that all the monkeys aren’t on the floor at the beginning.

输出

For each test case, print a line “Case #x: ”, where x is the case number (starting from 1) and print n integers. The i-th integer is the time monkey i drop in the floor. If monkey i don’t land on the floor, print -1;

样例输入
1
3 2
-1 3
3 -1
1 2
1 2
3 1
样例输出
Case #1: -1 1 1
提示

Tips:1≤T≤10,1≤n≤200,000,0≤m≤400,000
Initially, the first monkey’s tail hangs on the tree. The first monkey’s right hand catches the third monkey, the second monkey’s left hand catches the third monkey, and the third’s left hand catches the first monkey while the right hand catches the second. On time 0, the first monkey releases its right hand, no monkey lands on the floor. On time 1, the third monkey releases its left hand, then the second monkey and the third land on the floor.

题意

n 只猴子( 标号 1 - n ),m 个时刻 , 一开始给出 n 只猴子左右手牵的是哪只猴子( - 1 就是没牵),然后接下来 m 行给出每个时刻哪只猴子放开哪只手,最后让你给出 m 个时刻后,每只猴子在哪个时刻掉下去( - 1 代表没掉下去)(一开始只有 1 号猴子 尾巴 挂在树上)

思路

看猴子是不是掉下去就是判断和 1 是不是联通,可以倒着考虑这个题,把松手倒过来,看做从最后一次开始抓,用并查集启发式合并集合的那些元素,然后看看和 1 是不是连通,如果联通,就把答案时刻存下来。(还是看代码吧(((φ(◎ロ◎;)φ))))

代码
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define best 131 
#define INF 0x3f3f3f3f
#define P pair<int,int>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps=1e-7;
const double pai=acos(-1.0);
const int N=2e4+10;
const int maxn=4e5+10;
const int mod=1e9+7;
//const int d[4][2]={0,1,1,0,-1,0,0,-1};
int pre[maxn],ans[maxn];
vector<int>deep[maxn];
pair<int,int>p[maxn];
int vis[maxn][3],to[maxn][3];
int find(int x)
{
    if(pre[x]==x) return x;
    else return pre[x]=find(pre[x]);
} 
void unions1(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx==fy) return;
    if(deep[fx].size()>deep[fy].size()) swap(fx,fy);
    pre[fx]=fy;
    deep[fy].insert(deep[fy].end(),deep[fx].begin(),deep[fx].end());
}
void unions2(int x,int y,int t)
{
    if(y==-1) return;
    int fx=find(x);
    int fy=find(y);
    if(fx==fy) return;
    int f1=find(1);
    if(fx==f1)
    {
        for(int i=0;i<deep[fy].size();i++)
            ans[deep[fy][i]]=t;
    }
    if(fy==f1)
    {
        for(int i=0;i<deep[fx].size();i++)
            ans[deep[fx][i]]=t;
    }
    if(deep[fx].size()>deep[fy].size()) swap(fx,fy);
    pre[fx]=fy;
    deep[fy].insert(deep[fy].end(),deep[fx].begin(),deep[fx].end());
}
void init(int n)
{
    for(int i=1;i<=n;i++) 
    {
        deep[i].clear();
        pre[i]=i;ans[i]=-1;
        deep[i].push_back(i);
        vis[i][1]=0;vis[i][2]=0;
    }
}
int main()
{
//  ios::sync_with_stdio(false);
    //memset(mp,-1,sizeof(mp));
    int t,n,m,x,y,tot=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init(n);
        for(int i=1;i<=n;i++) 
        {
            scanf("%d%d",&x,&y);
            to[i][1]=x;to[i][2]=y;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&p[i].first,&p[i].second);
            vis[p[i].first][p[i].second]=1;
        } 
        for(int i=1;i<=n;i++) 
        {
            for(int j=1;j<=2;j++)
            {
                if(to[i][j]==-1||vis[i][j]) continue;
                unions1(i,to[i][j]);
            } 
        }
        for(int i=m;i>=1;i--) 
        {
            unions2(p[i].first,to[p[i].first][p[i].second],i-1);
        }
        printf("Case #%d: ",++tot);
        for(int i=1;i<n;i++) printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值