题解:AT_joisc2017_f 鉄道旅行 (Railway Trip)
题意
分析
非常神仙的倍增做法。
我们设
同理设
考虑如何更新这两个状态。
因为可以走回头路,所以简单的
我们可以考虑从两个端点来更新。
递推式如下:
每次查询时先从较左点向两侧扩展区间,如果该区间没有包含较右点,那么就扩展区间并统计答案。
然后再从较右点向两侧扩展区间,如果两区间没有交,那么扩展区间并统计答案。
最后得到的两区间再扩展一步就一定会有交。
Code
#include<bits/stdc++.h> using namespace std; #define maxn 100005 int lis[maxn], l[maxn][18], r[maxn][18], stk[maxn], *top=stk; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n, k, q; cin>>n>>k>>q; for(int i=1;i<=n;i++) cin>>lis[i]; for(int i=1;i<=n;i++) { while(top!=stk&&lis[*top]<lis[i]) top--; if(top!=stk) l[i][0]=*top; else l[i][0]=i; *++top=i; } top=stk; for(int i=n;i;i--) { while(top!=stk&&lis[*top]<lis[i]) top--; if(top!=stk) r[i][0]=*top; else r[i][0]=i; *++top=i; } for(int j=1;j<18;j++) for(int i=1;i<=n;i++) l[i][j]=min(l[l[i][j-1]][j-1], l[r[i][j-1]][j-1]), r[i][j]=max(r[l[i][j-1]][j-1], r[r[i][j-1]][j-1]); int a, b, ans; while(q--) { cin>>a>>b; ans=0; if(a>b) swap(a, b); int lx=a, rx=a; for(int i=17, nl, nr;~i;i--) { nl=min(l[lx][i], l[rx][i]); nr=max(r[lx][i], r[rx][i]); if(nr<b) lx=nl, rx=nr, ans+=1<<i; } a=rx; lx=rx=b; for(int i=17, nl, nr;~i;i--) { nl=min(l[lx][i], l[rx][i]); nr=max(r[lx][i], r[rx][i]); if(nl>a) lx=nl, rx=nr, ans+=1<<i; } cout<<ans<<'\n'; } }
本文作者:redacted-area
本文链接:https://www.cnblogs.com/redacted-area/p/18379540
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步