2910: 独木桥(bridge)

题目描述

 

Alice和Bob是好朋友,这天他们带了n个孩子一起走独木桥。

独木桥宽度很窄,不允许两个或两个以上的人并肩行走,所有人必须要前后一个接一个地通行。

Bob给所有的孩子蒙上了眼,并将他们放在桥中不同的位置上,孩子们初始的朝向不一定相同。Bob吹响哨声后这些孩子们会按照初始的朝向开始移动,当两个孩子移动到同一点时由于桥太窄他们无法穿过彼此,因此他们会同时转身改变朝向,并接着朝新方向移动。

为了安全起见,在某个时刻Alice会询问Bob某个孩子现在所处的位置。

更具体的,我们可以将问题抽象如下:

· 将独木桥看作一个长度无限长的实数轴,将每个孩子看作数轴上的一个实数点。数轴从左到右坐标不断增大。

· 孩子的位置用相对于数轴原点的点的坐标来表示。初始时n个点在n个互不相同的整点上。

· 每个点有一个初始朝向(从左向右或从右向左)。任何时刻所有的点都会以每秒1单位长度的速度匀速向所朝的方向移动。当某个时刻两个点同时移动到了同一个位置上,它们会立即改变自己的朝向(从左向右变成从右向左,反之亦然),然后继续移动。

·有qq次询问,每次询问给定kiki与titi,询问在titi秒后,孩子kiki目前的位置。

Bob无法同时关注这么多的孩子,请你帮帮他。

 

 

输入

 

第一行一个整数nn表示孩子数,孩子从00开始编号。

第二行nn个整数pipi,表示孩子们的初始位置。

第三行nn个整数didi,表示孩子们的初始朝向。di=0di=0则初始向左,di=1di=1则初始向右。

第四行一个整数qq 表示询问数。

接下来qq行每行两个整数ki,tiki,ti表示一个询问,询问在titi秒

后,孩子kiki (按输入顺序)目前的位置。

 

 

输出

 

输出q行每行一个整数表示答案。

 

 

样例输入

<span style="color:#333333"><span style="color:#333333">5
1 3 5 8 9
1 1 1 0 0
3
3 2
0 7
1 5</span></span>

样例输出

<span style="color:#333333"><span style="color:#333333">7
1
4</span></span>

提示

 

【样例2】 bridge.rar
【数据范围】

20%的数据:n,pi,ti≤10n,pi,ti≤10

另有20%的数据:di均相同

另有20%的数据:q≤10q≤10

另有15%的数据:ti≤100ti≤100

另有15%的数据:n≤1000n≤1000

1OO%的数据:1≤n,q≤2∗1051≤n,q≤2∗105, 0≤ki<n0≤ki<n, 0≤pi,ti≤1090≤pi,ti≤109,di∈0,1di∈0,1

 

 

来源

gwy

 

题解:

可能很多人都看过这道题的原型,所以我这个思路也就顺着原题的思路往下延伸。

原题的结论就是我们可以把每一只蚂蚁看作没有掉头,只是当他们相遇时,互相交换了一下自己的”号码牌“,然后继续沿着原来的方向前进,所以这题的思路有很明了了,就是要找到询问的“号码牌”最终交到了谁的手上。

仔细想一想,假设询问的蚂蚁是向右的,那么他的号码牌肯定是在交给右边遇到第一个想左的,然后是左边第一个向右的,然后是右边第二个向左的,左边第二个向右的……

所以我们把遇到一个向右的和一个向左的当作一轮回,我们可以通过预处理+二分出我们经历了多少个轮回。

之后只需要分类讨论出蚂蚁最终将号码牌交给了谁即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct Node{int a,b,id;}s[200005];
bool cmp(Node t1,Node t2){return t1.a<t2.a;}
int n,a[200005],b[200005],Q,sum1[200005],sum2[200005],tot1,tot2;
int pre1[200005],pre2[200005],nexl[200005],nexr[200005],las,dy[200005];
//s1 r s2 l pr1 i->tot1   pr2 i->tot2 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&s[i].a),s[i].id=i;
    for(int i=1;i<=n;++i)scanf("%d",&s[i].b);
    sort(s+1,s+1+n,cmp);
    for(int i=1;i<=n;++i)a[i]=s[i].a,b[i]=s[i].b,dy[s[i].id]=i;
    for(int i=1;i<=n;++i)
    {
        if(!b[i]){nexr[i]=las;continue;}
        ++tot1;
        if(las)sum1[tot1]=sum1[tot1-1]+a[i]-a[las];
        las=i;pre1[i]=tot1;
    }
    las=0;
    for(int i=n;i;--i)
    {
        if(b[i]){nexl[i]=las;continue;}
        ++tot2;
        if(las)sum2[tot2]=sum2[tot2-1]+a[las]-a[i];
        las=i;pre2[i]=tot2;
    }
    scanf("%d",&Q);
    while(Q--)
    {
        int t1,t2;
        scanf("%d%d",&t1,&t2);t1++;
        if(b[dy[t1]])
        {
            int l=1,k=dy[t1],t=nexl[k],r=min(pre1[k],pre2[t]),tim=0;
            if(!t){printf("%d\n",a[k]+t2);continue;}
            if(a[t]-a[k]>=t2*2){printf("%d\n",a[k]+t2);continue;}
            while(l<r)
            {
                int mid=l+r+1>>1;
                if(sum1[pre1[k]]-sum1[pre1[k]-mid+1]+sum2[pre2[t]]-sum2[pre2[t]-mid+1]+a[t]-a[k]<=t2*2)l=mid;
                else r=mid-1;
            }
            tim=sum1[pre1[k]]-sum1[pre1[k]-l+1]+sum2[pre2[t]]-sum2[pre2[t]-l+1]+a[t]-a[k];
             
            tim=2*t2-tim;
            if(l==pre1[k]){printf("%d\n",a[t]+sum2[pre2[t]]-sum2[pre2[t]-l+1]-t2);continue;}
            if(tim>=sum1[pre1[k]-l+1]-sum1[pre1[k]-l])printf("%d\n",a[k]-(sum1[pre1[k]]-sum1[pre1[k]-l])+t2);
            else printf("%d\n",a[t]+sum2[pre2[t]]-sum2[pre2[t]-l+1]-t2);
        }
        else
        {
            int l=1,k=dy[t1],t=nexr[k],r=min(pre1[t],pre2[k]),tim=0;
            if(!t){printf("%d\n",a[k]-t2);continue;}
            if(a[k]-a[t]>=2*t2){printf("%d\n",a[k]-t2);continue;}
            while(l<r)
            {
                int mid=l+r+1>>1;
                if(sum1[pre1[t]]-sum1[pre1[t]-mid+1]+sum2[pre2[k]]-sum2[pre2[k]-mid+1]+a[k]-a[t]<=t2*2)l=mid;
                else r=mid-1;
            }
            tim=sum1[pre1[t]]-sum1[pre1[t]-l+1]+sum2[pre2[k]]-sum2[pre2[k]-l+1]+a[k]-a[t];
            tim=2*t2-tim;
            if(l==pre2[k]){printf("%d\n",a[t]-(sum1[pre1[t]]-sum1[pre1[t]-l+1])+t2);continue;}
            if(tim>=sum2[pre2[k]-l+1]-sum2[pre2[k]-l])printf("%d\n",a[k]+sum2[pre2[k]]-sum2[pre2[k]-l]-t2);
            else printf("%d\n",a[t]-(sum1[pre1[t]]-sum1[pre1[t]-l+1])+t2);
        }
    }
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值