题解:P11021 「LAOI-6」区间测速
ICU152_lowa_IS8 · · 题解
这场比赛之前,我曾经祈祷最后两题不要出构造。
不知道是不是有更简便的解法,但在我看完题面并想好做法之后,突然就开始想念构造了,起码只用动脑子。
有点大的分讨。
首先得出一个结论:
假设
假设
-
如果
v_{ab}=v_{bc} ,那么最后的答案一定小于等于(小于还是等于和移动方向有关,可以自己画几个图)v_{ac} ; -
如果
v_{ab}\not=v_{bc} ,显然答案一定小于\max(v_{ab},v_{bc}) 。
用一张图来表示(假设每个监控的信息被抽象为一个点):
然后我们可以开始考虑如何执行题目的操作了。
有一个简单并且显而易见的思路:当一个点被修改,先得出该点拿掉之后该序列的最大值,然后再看这个点按照时间顺序插入之后的最靠近该点左右的两个点(这里用到了上面那个结论,想一想为什么)所提供的答案,将这三个结果取最大值。
还是用一张图表示:
这种做法可以解决一大部分情况,但万一修改到的红色点在两个蓝色段上呢?
简单,只要再维护一个第二大不就行了吗?
然后还是看图吧,更清楚:
这个方法可以解决很多问题,但还有一种特殊情况:如果修改到的红色点同时在两个段上呢?
简单,只要再维护一个第三大不就行了吗?
由于一个点一定不能同时覆盖到三个区间,因此我们不用再说“简单,只要再维护一个第四大不就行了吗?”
值得注意的是,我们统计的第一、第二、第三大只是长度为一的区间的大小顺序,所以我们才需要引入紫色段(这个长度为二的区间仍然可能大于第二大、第三大)。
思路大概到这里,至于代码……长度有点吓人,码量作为基础赛第三题感觉有点过于凶残了。
具体的实现方法还有一些实现上的细节本题解并未提及,可以参考于代码。
因为是比赛写的,所以代码没有经过任何优化也不简洁,并不值得借鉴。
代码没有注释,还请见谅。
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node{
int xi,ti,id;
}a[1000005];
bool cmp(node a,node b){
return a.ti<b.ti;
}
int f[1000005];
signed main(){
int n,m;
int maxn1=0,maxn2=0,maxi1=0,maxi2=0,maxn3=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i].xi>>a[i].ti;
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(int i=2;i<=n;i++){
// cout<<a[i].xi-a[i-1].xi<<" "<<a[i].ti<<" "<<a[i-1].ti<<endl;
if(maxn1<abs(a[i].xi-a[i-1].xi)/(a[i].ti-a[i-1].ti)){
maxn3=maxn2;
maxn2=maxn1;
maxi2=maxi1;
maxn1=abs(a[i].xi-a[i-1].xi)/(a[i].ti-a[i-1].ti);
maxi1=i-1;
}
else if(maxn2<abs(a[i].xi-a[i-1].xi)/(a[i].ti-a[i-1].ti)){
maxn3=maxn2;
maxn2=abs(a[i].xi-a[i-1].xi)/(a[i].ti-a[i-1].ti);
maxi2=i-1;
}
else if(maxn3<abs(a[i].xi-a[i-1].xi)/(a[i].ti-a[i-1].ti)){
maxn3=abs(a[i].xi-a[i-1].xi)/(a[i].ti-a[i-1].ti);
}
f[a[i].id]=i;
}
// cout<<"___________________________________________\n";
// cout<<maxn1<<" "<<maxn2<<" "<<maxn3<<"ASD\n";
while(m--){
int u,v;
cin>>u>>v;
u=f[u];
int nt=-1;
if(u==maxi1){
// cout<<"MAXI____\n";
if(u==maxi2+1){
nt=max(abs(a[maxi1+1].xi-a[maxi1-1].xi)/(a[maxi1+1].ti-a[maxi1-1].ti),maxn3);
}
else{
nt=max(abs(a[maxi1+1].xi-a[maxi1-1].xi)/(a[maxi1+1].ti-a[maxi1-1].ti),maxn2);
}
}
else if(u==maxi1+1){
// cout<<"MAXI++++\n";
if(u==maxi2){
// cout<<"@\n";
nt=max(abs(a[maxi1+2].xi-a[maxi1].xi)/(a[maxi1+2].ti-a[maxi1].ti),maxn3);
}
else{
nt=max(abs(a[maxi1+2].xi-a[maxi1].xi)/(a[maxi1+2].ti-a[maxi1].ti),maxn2);
}
}
else{
nt=maxn1;
}
// cout<<nt<<endl;
int l=1,r=n,mid,tmp=0;
while(l<=r){
mid=l+r>>1;
if(a[mid].ti<=v){
tmp=mid;
l=mid+1;
}
else{
r=mid-1;
}
}
int now=0;
// cout<<u<<"________________"<<tmp<<endl;
if(tmp==0){
if(u==1){
now=max(now,abs(a[2].xi-a[u].xi)/(a[2].ti-v));
}
else{
now=max(now,abs(a[1].xi-a[u].xi)/(a[1].ti-v));
}
}
else{
if(u==tmp&&tmp!=1){
now=max(now,abs(a[u].xi-a[tmp-1].xi)/(v-a[tmp-1].ti));
}
else{
// cout<<"ASDJKLAS\n";
// cout<<a[u].xi<<" "<<a[tmp].xi<<" "<<a[u].ti<<" "<<a[tmp].ti<<endl;
now=max(now,abs(a[u].xi-a[tmp].xi)/(v-a[tmp].ti));
}
if(u==tmp+1&&tmp!=n){
now=max(now,abs(a[tmp+2].xi-a[u].xi)/(a[tmp+2].ti-v));
}
else{
now=max(now,abs(a[tmp+1].xi-a[u].xi)/(a[tmp+1].ti-v));
}
}
cout<<max(nt,now)<<"\n";
}
return 0;
}