C - Robot Collisions
题目描述
有n个机器人沿着x轴线行驶。还有两个墙:一个在坐标0处,另一个在坐标m处。
第i个机器人以整数坐标 x i x_i xi( 0 < x i < m 0<x_i<m 0<xi<m )开始,以1单位/秒的速度向左(向右)移动。没有两个机器人从同一个坐标开始。
当一个机器人到达一堵墙时,它会立即转身,以同样的速度继续朝相反的方向行驶。
每当几个机器人在同一个整数坐标处相遇时,它们就会碰撞并爆炸成尘埃。一旦一个机器人爆炸了,它就不会和其他机器人相撞。请注意,如果多个机器人在非整数坐标处相遇,则什么也不会发生。
对于每个机器人,找出是否发生过爆炸,如果发生了爆炸,输出爆炸的时间,否则输出-1。
数据范围与提示
2 ≤ n ≤ 300000 2\le n\le 300000 2≤n≤300000 。
思路
首先由于机器人只有恰好走在整数坐标时相撞才爆炸,所以坐标奇偶性不同的机器人一定不相撞。容易发现,机器人的坐标沿着墙对称过去后的奇偶性不变,也就是说,两个坐标奇偶性相同的机器人,其中一个遇墙反弹后,它们奇偶性仍相同。所以我们可以把奇偶坐标分开来讨论。
另外,奇偶性相同的机器人一定不会互相越过,相遇就爆炸。而且由于初始坐标不相同,爆炸一定是两个机器人相撞,不会是三个及以上。然后问题就转换成机器人两两配对。
另外我们还发现,无论什么时候,面向墙的离墙最近的机器人的行进都可以等效于坐标沿墙对称、方向反向,而两个最近的方向相对的机器人一定会先爆炸、消失,然后给其它机器人让路。
所以这就是一个简单的括号匹配问题。
我们只需要每次把靠左边墙的右括号对称反向后再与后面的配对,最后倒着处理掉剩下的左括号即可。复杂度只有排序的 O ( n log n ) O(n\log n) O(nlogn) ,也可以用基排优化到 O ( n ) O(n) O(n) 。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#define ll long long
#define MAXN 300005
#define uns unsigned
#define INF 0x3f3f3f3f
using namespace std;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
return f?x:-x;
}
int n,a[MAXN];
ll x[MAXN],m,e[MAXN];
bool t[MAXN];
stack<int>st;
inline bool cmp(int c,int d){return x[c]<x[d];}
int main()
{
for(int T=read();T--;){
n=read(),m=read();
for(int i=1;i<=n;i++)x[i]=read(),a[i]=i;
for(int i=1;i<=n;i++){
char s=getchar();
while(s!='L'&&s!='R')s=getchar();
t[i]=(s=='L');
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)e[i]=0;
while(!st.empty())st.pop();
for(int K=1;K<=n;K++){
int i=a[K];
if(x[i]&1){
if(t[i]&&st.empty())t[i]=0,x[i]=-x[i];
if(t[i]){
int u=st.top();st.pop();
e[u]=e[i]=(x[i]-x[u])>>1;
}
else st.push(i);
}
}
while(st.size()>1){
int v=st.top();st.pop();
int u=st.top();st.pop();
x[v]=(m<<1)-x[v];
e[u]=e[v]=(x[v]-x[u])>>1;
}
while(!st.empty())st.pop();
for(int K=1;K<=n;K++){
int i=a[K];
if((~x[i]&1)&&x[i]>0){
if(t[i]&&st.empty())t[i]=0,x[i]=-x[i];
if(t[i]){
int u=st.top();st.pop();
e[u]=e[i]=(x[i]-x[u])>>1;
}
else st.push(i);
}
}
while(st.size()>1){
int v=st.top();st.pop();
int u=st.top();st.pop();
x[v]=(m<<1)-x[v];
e[u]=e[v]=(x[v]-x[u])>>1;
}
for(int i=1;i<=n;i++)
printf("%lld ",e[i]>0?e[i]:-1);
putchar('\n');
}
return 0;
}