问题描述
某城市有n个小镇,编号是1~n。由于贫穷和缺乏城市规划的人才,每个小镇有且仅有一段单向的公路通往别的小镇。有一天,一辆小轿车误入了这座城市,它只能沿着公路走,它走啊走,却再也走不出这座城市了……问如果这辆车从某个小镇出发,走了若干段公路,会到达哪个小镇。每组数据有m个询问。
输入格式
第一行两个数n、m:表示小镇数和询问数;
接下来一行n个数,第i个数Ai:表示从小镇i出发的公路会通向小镇Ai;
接下来m行,第i行有两个数Bi和Ci:询问小轿车从小镇Bi出发,走过Ci段路后会达到哪个小镇。
输出格式
一行m个数回答每个询问。
样例输入
3 3
2 1 3
1 1
2 2
3 3
样例输出
2 2 3
数据规模和约定
对于60%的数据:1<=n、m<=1000,1<=Ai、Bi<=n,0<=Ci<=1000;
对于100%的数据:1<=n、m<=100000,1<=Ai、Bi<=n,0<=Ci<=100000。
解题思路:
这道题是一道经典的利用倍增思想的题,用暴力的话只能拿到60%的测试点,剩下的会运行超时。
那么,什么是倍增法呢?倍增法就是利用任何一个数都能用2的n次方表示,例如13的二进制为1101,那么13就可以用2的3次方+2的2次方+2的0次方表示。所以我们只需要先预处理一下数据,求得每个小镇跳2的n次方步会到达哪个小镇就可以啦。要计算从s小镇跳2的n次方步到哪里的公式为go[s][n]=go[go[s][n-1]][n-1]。
等式的右边go[s][n-1]的含义为从s小镇跳2的n-1次方个区间到达的小镇,我们假设到达的小镇为t,所以go[go[s][n-1]][n-1]=go[t][n-1],表示从t小镇跳2的n-1次方达到的小镇,所以全部过程是先从s小镇跳2的n-1次方步到达t小镇,再从t小镇跳2的n-1次方步达到终点,总共跳了2的n-1次方+2的n-1次方步=2的n次方步。由于m<=100000,所以我们只需要计算到每个小镇跳最多2的17次方步就可以啦。
倍增法只能用于静态的数据的预处理。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAX=100005;
int rode[MAX][19];
int n,m;
int main()
{
int i,j;
cin>>n>>m;
for(i=1;i<=n;i++) cin>>rode[i][0];
for(i=1;i<18;i++)
{
for(j=1;j<=n;j++)
{
rode[j][i]=rode[rode[j][i-1]][i-1];//倍增重要公式
}
}
for(i=1;i<=m;i++)
{
int a,b,count=0;//count用来表示现在是n的几次方步了
cin>>a>>b;
while(b!=0)
{
if(b%2==1) a=rode[a][count];//如果为1则需要跳步
b/=2;
count++;
}
cout<<a<<" ";
}
}