2019ICPC 徐州 网络赛 B题 so easy E题 XKC's basketball team

哎,感觉这题出的很常规,也很简单,可比赛的时候就是想不起来......

 B题 so easy 题目链接

题意:输入n,q表示右1到n这n个数按从小到大的顺序排列,初始状态这n个数都是有效值,然后q次操作,1 x 表示将x置为无效值,2 x表示询问x到n中第一个有效值为多少,输出这个有效值。

并查集就行了......

AC代码:747ms(unordered_map 确实比 map 快不少,map 要1723ms,unordered_map 只要747ms)

#include<bits/stdc++.h>
#include <tr1/unordered_map>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
int n;
//map<int,int> fa;
tr1::unordered_map<int, int>fa;
int findfa(int x)
{
    if(fa.count(x)==0)
        return x;
    return fa[x]=findfa(fa[x]);
}
int main()
{
    int q;
    scanf("%d%d",&n,&q);
    int z,x;
    while(q--)
    {
        scanf("%d%d",&z,&x);
        if(z==1)
            fa[x]=findfa(x+1);
        else
        {
            int ans=findfa(x);
            if(ans>n)
                ans=-1;
            printf("%d\n",ans);
        }
    }
    return 0;
}

E题 XKC's basketball team 题目链接

题意:给定一个序列,从每一个数后面比它大至少 m 的数中求出与它之间最大的距离。 如果没有则为 -1。

对于每一个数,利用二分的方法求他右边大于等于ai+m的数的最后一个值。

关键在于怎么二分呢?
利用线段树或ST表在 log n 时间内求区间最大值,看这个区间的最大值是不是比ai+m大。

AC代码:747ms

#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
int n,a[500010];
int f[500010][21];
int ans[500010];
void ST_prework()
{
    for(int i=1;i<=n;i++)
        f[i][0]=a[i];
    int t=log(n)/log(2)+1;
    for(int j=1;j<t;j++)
        for(int i=1;i<=n-(1<<j)+1;i++)
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int ST_query(int l,int r)   //返回a[l]到a[r]中的最大值
{
    int k=log(r-l+1)/log(2);
    return max(f[l][k],f[r-(1<<k)+1][k]);
}
bool ok(int l,int r,int x)
{
    if(ST_query(l,r)>=x)
        return true;
    return false;
}
int main()
{
    int m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    ST_prework();
    for(int i=1;i<=n;i++)
    {
        int p=-1;
        int l=i,r=n;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(ok(mid,r,a[i]+m))
                l=mid+1,p=max(p,mid);
            else
                r=mid-1;
        }
        if(a[l]>=a[i]+m)
            p=max(p,l);
        if(p==-1)
            ans[i]=-1;
        else
            ans[i]=p-i-1;
    }
    for(int i=1;i<=n;i++)
    {
        if(i!=n)
            printf("%d ",ans[i]);
        else
            printf("%d",ans[i]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值