【GDOI2018模拟8.7】的士碰撞

来源:互联网 发布:知荣制衣 联系方式 编辑:程序博客网 时间:2024/04/28 03:14

Description

n辆车在一条数轴上,车的编号为1到n。编号为i的车坐标为a[i],初始方向为dir[i](左或右),初始位置两两不同。每辆车每个时刻行走距离为1。两辆车相碰时,会调转方向,继续行走,掉头不消耗时间。现在车子开始朝其方向行驶,同一个坐标允许有多辆车。现在有q个询问,给出 t,i,询问过了t时刻后,编号为i的车的坐标的绝对值。

Input

输入文件名为collision.in。
首先输入n,q 。
接下来n行,每行两个整数a[i],dir[i],若dir[i]=0,表示车子向左行走,若dir[i]=1,表示车子向右行走。
接下来 q行,每行两个整数t,i ,询问时刻 t时编号为i 的车的坐标。

Output

输出文件名为collision.out。
对于每个询问,输出一个整数,代表编号为i的车的坐标。

Sample Input

输入1:
5 5
1 1
4 1
2 0
7 1
11 0
5 1
10 2
7 3
8 4
20 5

输入2:
20 15
31116973 1
721410312 0
152891538 1
55434456 0
903968 1
34492580 0
97565125 0
78559065 1
191708700 0
335941230 0
526621966 1
168159348 1
457798506 1
160026937 1
76511872 1
247171016 1
48722268 0
159552820 0
701333640 0
434868520 1
143857480 13
821356724 11
132436670 1
20249229 11
504666 16
138701034 19
339607872 1
184664000 13
80827802 15
625365533 5
668115287 6
93821572 7
175176488 5
438184710 1
71279702 12

Data Constraint

n,q<=100000
0<=a[i]<=109
t<=109

Solution

这题真的太妙了
两个车碰撞,相当于两个车互相穿过,编号互换
而且无论怎么碰撞,车辆之间的相对位置是不会改变的
比如说1号车在2号车左边
那么2号车无论怎么撞都不可能跑到1号车左边
那么t时刻后每辆车的位置就是a[i]+/-t
这时给出要求的车的编号,我们知道这个编号的车初始时的排名,设为y
那么答案就是所有车中排名为y的那辆车的坐标


这个二分坐标mid
那么就是要求有多少车在这个坐标前面
将车往左和往右的分为两种
在往左的车中二分求出初始位置为mid+t之前的有多少
往右的车中二分求出初始位置为mid-t之前有多少
就可以得出答案了

PS
二分有个upper_bound和lower_bound
upper_bound是求出>k的第一个位置
lower_bound是求出>=k的第一个位置
这题中第二个二分一个简单方法就是upper_bound出位置之后-1

Code

#include<cstring>#include<algorithm>#include<cmath>#define fo(i,a,b) for(int i=a;i<=b;i++)#define N 101000#define INF 10000000000ll#define ll long longusing namespace std;ll n,m,b[N],c[N],ans[N],t1=0,t2=0,d[N];struct node{    ll x,y,z;}a[N];bool cnt(node x,node y){return x.x<y.x;}int main(){    freopen("collision.in","r",stdin);    freopen("collision.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,n) scanf("%lld%lld",&a[i].x,&a[i].y),a[i].x+=INF,a[i].z=i;    sort(a+1,a+n+1,cnt);    fo(i,1,n)    {        d[a[i].z]=i;        if(a[i].y==0) c[++t2]=a[i].x;        else b[++t1]=a[i].x;    }    b[++t1]=INF+INF+INF+2;    c[++t2]=INF+INF+INF+2;    fo(i,1,m)    {        ll x,y;scanf("%lld%d",&x,&y);        ll l=0,r=INF+INF+INF+INF;        while(l+1<r)        {            ll mid=(l+r)/2,ans=0;            ll z=upper_bound(b+1,b+t1+1,mid-x)-b-1;            z=z+upper_bound(c+1,c+t2+1,mid+x)-c-1;            if(z<d[y]) l=mid;else r=mid;        }        printf("%lld\n",abs(r-INF));    }}
原创粉丝点击