CF1142E/1143B Lynyrd Skynyrd

  • 开始读错题了,以为是连续的一段,敲完后才发现是 \(subsequence\) ...
  • 考虑对于 \(a\) 中的每个 \(a_i\) 找到它在排列 \(p\) 中的下一个元素的最左位置 \(j\) ,从 \(i\)\(j\) 连一条边,这样就形成了一个森林.
  • 然后 \(dfs\) 遍历一下,用一个栈来存储当前在路径中的点,若当前节点为 \(u\) ,而路径长 \(\geq n\) ,说明路径中从 \(u\) 开始的 \(n\) 个位置构成了一个 \(cyclic\ shift\) .
  • 这样就可以处理出以点 \(i\) 为第一个元素,能找到的 \(cyclic\ shift\) 最后一个元素的最左位置 \(minr_i\).对这个东西取一下后缀 \(\min\) ,则它表示后缀 \(i\sim n\) 中能找到的 \(cyclic\ shift\) 最后一个元素的最左位置 .
  • 对于每个询问 \((l,r)\) ,只需判断是否有 \(r \leq minr_l​\) 即可.
  • 时间复杂度 \(O(n+Q)\).
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define mp make_pair
inline int read()
{
	int out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		fh=-1,jp=getchar();
	while (jp>='0'&&jp<='9')
		out=out*10+jp-'0',jp=getchar();
	return out*fh;
}
const int MAXN=2e5+10;
int n,m,Q;
int a[MAXN],b[MAXN],nxp[MAXN];
int pos[MAXN];
queue<char> buf;
int cnt=0,head[MAXN],to[MAXN],nx[MAXN];
inline void addedge(int u,int v)
{
	++cnt;
	to[cnt]=v;
	nx[cnt]=head[u];
	head[u]=cnt;
}
int vis[MAXN];
int minr[MAXN];
int stk[MAXN],tp=0;
void dfs(int u)
{
	vis[u]=1;
	stk[++tp]=u;
	if(tp>=n)
		minr[u]=min(minr[u],stk[tp-n+1]);
	for(int i=head[u];i;i=nx[i])
	{
		int v=to[i];
		if(!vis[v])
			dfs(v);
	}
	--tp;
}
int main()
{
	n=read(),m=read(),Q=read();
	for(int i=1;i<=n;++i)
		a[i]=read();
	for(int i=1;i<=m;++i)
		b[i]=read();
	a[0]=a[n],a[n+1]=a[1];
	for(int i=1;i<=n;++i)
		nxp[a[i]]=a[i+1];
	for(int i=m;i>=1;--i)
	{
		pos[b[i]]=i;
		int pre=nxp[b[i]];
		if(pos[pre])
			addedge(pos[pre],i);
	}
	memset(minr,0x7f,sizeof minr);
	for(int i=m;i>=1;--i)
	{
		if(!vis[i])
			dfs(i);
		minr[i]=min(minr[i],minr[i+1]);
	}
	while(Q--)
	{
		int l=read(),r=read();
		if(minr[l]<=r)
			buf.push('1');
		else
			buf.push('0');
	}
	while(!buf.empty())
	{
		putchar(buf.front());
		buf.pop();
	}
	return 0;
}

相关文章:

猜你喜欢
  • 2022-02-26
  • 2021-11-19
  • 2022-12-23
  • 2021-09-30
  • 2021-10-27
  • 2022-03-05
相关资源
相似解决方案