UVALive 5789 Army Buddies 解题报告

比赛总结

题目

题意:

s个士兵排成一列,每次有L到R这些原本健在的士兵死亡,求L-1到1第一个还活着的士兵的编号,以及R+1到s第一个活着的士兵的编号,不存在则输出*。

题解:

方法一:

用并查集,将两种查询分开,如第一个并查集,L到R合并在一起,根为L,表示L+1到R这些人都死了,且R+1和L还活着,那么L到1第一个还活着的士兵自然是L。由于每个士兵只修改一次,所以是O(N)的。

方法二:

用线段树,每个节点记录一个l和r,分别表示最右边第一个活着的士兵的编号和最左边第一个活着的士兵的编号。若L到R的人死了,那么分别查询1到L-1最大的l和R+1到s最小的r。然后将查询的值输出后覆盖到L到R这个区间内。


//Time:172ms
//Length:1095B
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
const int MAXN = 100010;
using namespace std;
int fal[MAXN],far[MAXN];
int findfa(int n,int arr[])
{
    if(arr[n]!=n)    arr[n]=findfa(arr[n],arr);
    return arr[n];
}
void sub(int a,int b,int arr[])
{
    a=findfa(a,arr),b=findfa(b,arr);
    arr[b]=a;
}
int cal2(int l,int r)
{
    for(int i=l;i<=r;)
        sub(i+1,i,far),i=findfa(i,far);
    return findfa(l,far);
}
int cal1(int r,int l)
{
    for(int i=r;i>=l;)
        sub(i-1,i,fal),i=findfa(i,fal);
    return findfa(l,fal);
}
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    int s,b;
    while(scanf("%d%d",&s,&b)&&s&&b)
    {
        for(int i=0;i<=s+1;++i)   fal[i]=far[i]=i;
        int l,r;
        for(int i=0;i<b;++i)
        {
            scanf("%d%d",&l,&r);
            int tmp=cal1(r,l);
            if(tmp==0)  printf("* ");
            else    printf("%d ",tmp);
            tmp=cal2(l,r);
            if(tmp==s+1)  printf("*\n");
            else    printf("%d\n",tmp);
        }
        printf("-\n");
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值