CF863D题解

注意:这篇题解是写给像我这样不会那个什么什么平衡树的萌新看的,大佬请自动跳过。

简单易懂的解法:倒推

回归正题。

这题如果是暴力的话,时间复杂度为 O(nq)O(nq),肯定是会炸的,于是就可以利用 mm 很小这特殊性质,把时间复杂度跟 mm 扯上关系,于是就想到了倒推。

怎么倒推呢?其实很简单。

先讲明白正序的操作吧

  • 如果 ti=1t_i=1,不妨设当前下标为 xx:
    \circ 如果 x<lix\lt l_i 或者 x>rix\gt r_i(既 xx 在操作区间的外面)则不做操作。
    \circ 反之,xx 在操作区间的里面,如果 x=rix=r_i,则 xlix\gets l_i,否则 xx+1x\gets x+1
  • 如果 ti=2t_i=2,同理,不妨设当前下标为 xx:
    \circ 如果 x<lix\lt l_i 或者 x>rix\gt r_i(既 xx 在操作区间的外面)则不做操作。
    \circ 反之,xx 在操作区间的里面,由于是对翻转操作,设 xx 的翻转后在 xx',则满足一个性质:x+x=li+rix+x'=l_i+r_i,所以 xli+rixx\gets l_i+r_i-x

那再来看看倒序的情况。

首先,记录当前的下标 nowbnow_b,初值 nowb=binow_b=b_i
从后往前倒序枚举每个操作,计这是第 jj 个操作:

  • 如果 ti=1t_i=1:
    \circ 与正序一样,如果 nowb<linow_b\lt l_i 或者 nowb>rinow_b\gt r_i(既 nowbnow_b 在操作区间的外面)则不做操作。
    \circ 反之,nowbnow_b 在操作区间的里面,操作即为正序的撤销操作,如果 x=lix=l_i,则 nowbrinow_b\gets r_i,否则 nowbnowb1now_b\gets now_b-1
  • 如果 ti=2t_i=2:
    \circ 与正序一样,如果 nowb<linow_b\lt l_i 或者 nowb>rinow_b\gt r_i(既 nowbnow_b 在操作区间的外面)则不做操作。
    \circ 反之,nowbnow_b 在操作区间的里面,操作其实与正序时一样,由于是对翻转操作,设 nowbnow_b 的翻转后在 nowbnow_b'nowbli+rinowbnow_b\gets l_i+r_i-now_b

最后输出 anowba_{now_b} 即可。

代码,仅供参考

#include<bits/stdc++.h>
using namespace std;
int n,m,q,a[200010],t[200010],l[200010],r[200010];
int main(){
	scanf("%d%d%d",&n,&q,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=q;i++) scanf("%d%d%d",&t[i],&l[i],&r[i]);
	for(int i=1;i<=m;i++){
		int b;
		scanf("%d",&b);
		for(int j=q;j>=1;j--){
			if(l[j]>b||r[j]<b) continue;
			if(t[j]==1){
				if(b==l[j]) b=r[j];
				else b--;
			}
			else b=l[j]+r[j]-b;
		}
		printf("%d ",a[b]);
	}
	return 0;
}
posted @ 2023-03-18 21:47  fengxiaoyi  阅读(24)  评论(0)    收藏  举报  来源