[CF1142B] Lynyrd Skynyrd

问题描述

Recently Lynyrd and Skynyrd went to a shop where Lynyrd bought a permutation p of length n, and Skynyrd bought an array a of length mm, consisting of integers from 1 to n.

Lynyrd and Skynyrd became bored, so they asked you q queries, each of which has the following form: "does the subsegment of a from the l-th to the r-th positions, inclusive, have a subsequence that is a cyclic shift of p?" Please answer the queries.

A permutation of length n is a sequence of n integers such that each integer from 1 to n appears exactly once in it.

A cyclic shift of a permutation (p1,p2,…,pn) is a permutation (pi,pi+1,…,pn,p1,p2,…,pi−1)for some ii from 1 to n. For example, a permutation (2,1,3) has three distinct cyclic shifts: (2,1,3), (1,3,2), (3,2,1).

A subsequence of a subsegment of array a from the l-th to the r-th positions, inclusive, is a sequence ai1,ai2,…,aik for some i1,i2,…,i such that l≤i1<i2<…<ik≤r.

输入格式

The first line contains three integers n , m , q(( 1 le n, m, q le 2 cdot 10^5 )) — the length of the permutation p , the length of the array a and the number of queries.

The next line contains n integers from 1 to n , where the i-th of them is the i -th element of the permutation. Each integer from 1 to n appears exactly once.

The next line contains m integers from 1 to n, the i -th of them is the i-th element of the array a .

The next q lines describe queries. The i -th of these lines contains two integers li and ri ($ 1 le l_i le r_i le m )$, meaning that the i -th query is about the subsegment of the array from the li-th to the ri-th positions, inclusive.

输出格式

Print a single string of length q , consisting of 0 and 1 , the digit on the i -th positions should be 1 , if the subsegment of array a from the li-th to the ri-th positions, inclusive, contains a subsequence that is a cyclic shift of p , and 0 otherwise.

题目翻译

洛谷

解析

可以观察到一个性质:一个循环排列除了开头的元素,其余元素前面是哪个数是唯一的。所以,我们利用这一点,设(to[i])表示元素i在排列中的下一个数是什么。如果i是最后一个,(to[i])就是第一个。对于原来的序列a的每一个元素(a[i]),都从后面最近的(to[a[i]])的位置向i连一条有向边。位置最近是为了保证回答询问时尽可能的合法。

可以发现,最后得到的是一个森林。只要从根节点遍历每一棵树,用一个栈记录当前在递归中的点。如果点的数量大于等于 n,说明找到了一个合法的循环排列,开头的位置是(s[top-n+1]),那么离开头最近的循环排列的结束位置就是当前点。

有了这些信息,我们可以回答每一个询问了。记(minp[i])表示以i为起点的循环排列最近的结束位置。对minp做后缀最小值,那么(minp[i])就表示i之后最近的循环排列结束在哪里。对于每个询问,只要看(minp[l])是否小于等于(r)即可。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define N 200002
using namespace std;
int head[N],ver[N*2],nxt[N*2],l;
int n,m,q,i,p[N],a[N],minp[N],pos[N],to[N],top,s[N];
bool vis[N];
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
void insert(int x,int y)
{
	l++;
	ver[l]=y;
	nxt[l]=head[x];
	head[x]=l;
}
void dfs(int x)
{
	vis[x]=1;
	s[++top]=x;
	if(top>=n) minp[x]=s[top-n+1];
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(!vis[y]) dfs(y);
	}
	top--;
}
int main()
{
	n=read();m=read();q=read();
	for(i=1;i<=n;i++) p[i]=read();
	for(i=1;i<=m;i++) a[i]=read();
	for(i=1;i<=n;i++) to[p[i]]=p[i%n+1];
	for(i=m;i>=1;i--){
		if(pos[a[i]]==0||pos[a[i]]>i) pos[a[i]]=i;
		if(pos[to[a[i]]]!=0){
			insert(pos[to[a[i]]],i);
		}
	}
	memset(minp,0x3f,sizeof(minp));
	for(i=m;i>=1;i--){
		if(!vis[i]) dfs(i);
	}
	for(i=m-1;i>=1;i--) minp[i]=min(minp[i],minp[i+1]);
	for(i=1;i<=q;i++){
		int l=read(),r=read();
		if(minp[l]<=r) printf("1");
		else printf("0");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/LSlzf/p/11725736.html