可以在 cnblog 中阅读。
考虑弱化版链怎么做,每次选取左端点在当前位置前面的线段,跳到其中最大的右端点,可以维护一个数组表示起点为 \(i\) 的目标位置,可以做到 \(O(n+k)\)。
考虑多次询问一段区间 \([l,r]\) 的答案,这时如果暴力从 \(l-1\) 开始跳是 \(O(n^2)\) 的,只需要一个倍增数组即可 \(O(\log n)\) 完成跳跃动作。
原题的做法也与之类似,一个处理环状问题的经典操作是复制一倍数组。这时对于复制后每个长度为 \(n\) 的区间都代表原环上的一个循环置换,那通过上面的区间询问做法,可以对每个长度为 \(n\) 的区间做询问,取答案最小值即为答案。
时间复杂度 \(O(n \log n)\)。
#include <bits/stdc++.h>
using namespace std;
// #define int long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
typedef pair<int,int> pii;
const int N=1e6+5,LG=25;
int n,k;
pii a[N];
int f[N*2][LG];
signed main()
{
IOS;
cin>>n>>k;
for(int i=1;i<=k;i++)
{
cin>>a[i].first>>a[i].second;
if(a[i].first>a[i].second) a[i].second+=n;
}
sort(a+1,a+k+1);
int r=0,tot=0;
for(int i=1;i<=n*2;i++)
{
while(tot+1<=k&&a[tot+1].first<=i)
r=max(r,a[++tot].second+1);
f[i][0]=r;
}
for(int j=1;j<=20;j++)
for(int i=1;i<=n*2;i++)
f[i][j]=f[f[i][j-1]][j-1];
int ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
int p=i,res=0;
for(int j=20;j>=0;j--)
{
if(f[p][j]<i+n)
p=f[p][j], res+=(1<<j);
}
res++, p=f[p][0];
if(p>=i+n) ans=min(ans,res);
}
if(ans>=0x3f3f3f3f) cout<<"impossible"<<endl;
else cout<<ans<<endl;
return 0;
}
标签:ICPC2014,int,题解,Surveillance,second,数组,ans,区间
From: https://www.cnblogs.com/tai-chi/p/18441961