1. 程式人生 > >2018.11.03-dtoj-2910-獨木橋(bridge)

2018.11.03-dtoj-2910-獨木橋(bridge)

題目描述:

Alice和Bob是好朋友,這天他們帶了n個孩子一起走獨木橋。

獨木橋寬度很窄,不允許兩個或兩個以上的人並肩行走,所有人必須要前後一個接一個地通行。

Bob給所有的孩子蒙上了眼,並將他們放在橋中不同的位置上,孩子們初始的朝向不一定相同。Bob吹響哨聲後這些孩子們會按照初始的朝向開始移動,當兩個孩子移動到同一點時由於橋太窄他們無法穿過彼此,因此他們會同時轉身改變朝向,並接著朝新方向移動。

為了安全起見,在某個時刻Alice會詢問Bob某個孩子現在所處的位置。

更具體的,我們可以將問題抽象如下:

· 將獨木橋看作一個長度無限長的實數軸,將每個孩子看作數軸上的一個實數點。數軸從左到右座標不斷增大。

· 孩子的位置用相對於數軸原點的點的座標來表示。初始時n個點在n個互不相同的整點上。

· 每個點有一個初始朝向(從左向右或從右向左)。任何時刻所有的點都會以每秒1單位長度的速度勻速向所朝的方向移動。當某個時刻兩個點同時移動到了同一個位置上,它們會立即改變自己的朝向(從左向右變成從右向左,反之亦然),然後繼續移動。

·有q次詢問,每次詢問給定ki與ti,詢問在titi秒後,孩子ki目前的位置。

Bob無法同時關注這麼多的孩子,請你幫幫他。

輸入:

第一行一個整數n表示孩子數,孩子從0開始編號。

第二行n個整數pi,表示孩子們的初始位置。

第三行n個整數di,表示孩子們的初始朝向。di=0則初始向左,di=1則初始向右。

第四行一個整數q 表示詢問數。

接下來q行每行兩個整數ki,ti表示一個詢問,詢問在titi秒

後,孩子ki (按輸入順序)目前的位置。

輸出:

輸出q行每行一個整數表示答案。

資料範圍:

20%的資料:n,pi,ti≤10n,

另有20%的資料:di均相同

另有20%的資料:q≤10

另有15%的資料:ti≤100

另有15%的資料:n≤1000

1OO%的資料:1≤n,q≤2∗105  0≤ki<n 0≤pi,ti≤109 di∈0,1

 演算法標籤:二分

思路:

這題的簡單版是螞蟻,妙的地方在於兩個孩子相撞繼續走,其實相當於像個孩子交換編號繼續不改方向的前行,所以其實最後有孩子的位置就是按原方向向前t的座標,至於每個孩子的位置在哪,由於每個孩子的排名始終不改變,即一個孩子的左右孩子的個數始終不變。所以我們可以把兩個方向的孩子放在兩個不同數組裡,每次二分一個答案座標,然後求出這個左邊的排名,效率是O(n*logn*log1e9)。

另一個nlogn的演算法相對難寫,似乎是用線段樹維護。

以下程式碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define re register
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=2e5+5,inf=2e9;
int n,tot1,tot2,pos[N];struct node{int p,id,d;}t[N];int q1[N],q2[N];
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
bool cmp(node t1,node t2){return t1.p<t2.p;}
int pd(LL x,int t){
    int res1,res2;
    res1=upper_bound(q1+1,q1+1+tot1,x-t)-q1;res1--;
    res2=upper_bound(q2+1,q2+1+tot2,x+t)-q2;res2--;
    return res1+res2;
}
int main()
{
    n=read();for(re int i=1;i<=n;i++){
        t[i].p=read();t[i].id=i;
    }
    for(re int i=1;i<=n;i++)t[i].d=read();
    sort(t+1,t+1+n,cmp);
    for(re int i=1;i<=n;i++)pos[t[i].id]=i;
    for(re int i=1;i<=n;i++){
        if(t[i].d==0)q2[++tot2]=t[i].p;
        else q1[++tot1]=t[i].p;
    }
    int Q=read();while(Q--){
        int k=pos[read()+1],tt=read();
        int l=t[1].p-tt,r=t[n].p+tt,res;res=r;
        while(l<=r){
            LL mid=(((LL)l+(LL)r)>>1ll);
            if(pd(mid,tt)>=k)res=mid,r=mid-1;else l=mid+1;
        }
        printf("%d\n",res);
    }
  return 0;
}
View Code