CodeForces - 1142B Lynyrd Skynyrd 倍增+思维

这个题很多地方都想到了 最后卡在了倍增优化  

显然一开始给了一个环 我们可以找出每个值的前驱  当我们遍历a数组的时候 我们需要找出最小的包含一个循环的区间  为啥是最小呢  假如 这个循环是  3 1 2   然后a数组是 3 3 1 2   显然对于r=4的时候 l=2是最小区间  对于l<2的情况我们都是认为满足条件的  而相反我们不能把l=1作为最小区间  

所以对于每个r我们需要找出包含一个循环的最大的l (我们用ans数组来记录这个值)以此来判断询问是否ok 

我们思考一下 当我们遍历到a数组的一个值时 我们可以根据pre数组向前走n-1步 最后走到的这个位置肯定是包含一个循环区间的(如果走到0说明不包含一个完整的循环 但是不影响询问) 

但是我们肯定不能暴力的去走这n-1步  这样复杂度是n^2的  

我们可以根据前驱记录父亲结点   然后用类似lca的方法(倍增法)  将n-1步进行二进制分解  从而在logn的时间内完成这个操作  不过根据第i个点走出来的l不一定是最大的l 所以我们要与ans[i-1]比较找出最大值 具体看代码

 

#include<bits/stdc++.h>
using namespace std;
int n,m,q;
const int N = 2e5+10;
const int inf = 1e9+1; 
int p[N],a[N],pre[N],pos[N],ans[N],f[N][30],k[N];
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i = 1; i <= n; i++) scanf("%d",&p[i]);
	for(int i = 1; i <= m; i++) scanf("%d",&a[i]);
	for(int i = 2; i <= n; i++) pre[p[i]]=p[i-1];
	pre[p[1]]=p[n];
	int g = (int)(log(n)/log(2))+1;
	k[0]=1;
	for(int i = 1; i <= g; i++) k[i]=k[i-1]*2; 
	for(int i = 1; i <= m; i++){
		f[i][0]=pos[pre[a[i]]];
		for(int j = 1; j <= g; j++)//f数组初始化
		f[i][j]=f[f[i][j-1]][j-1];
		pos[a[i]]=i;
	} 
	for(int i = 1; i <= m; i++){
		int now = n-1,x = i;//now表示要走的步数 x表示当前结点
		for(int j = g; j >= 0; j--){
			if(now>=k[j]){//二进制拆分这个步数
				now-=k[j];
				x=f[x][j];
			}
		}
		ans[i]=max(ans[i-1],x);//选择最大l
	}
	for(int i = 1; i <= q; i++){
		int l,r;
		scanf("%d%d",&l,&r);
		if(ans[r]>=l) printf("1");//这就是为啥ans[r]=0也不影响 因为这样对所有的询问也是输出0
		else printf("0");
	}
	puts("");
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值