CF863D题解
注意:这篇题解是写给像我这样不会那个什么什么平衡树的萌新看的,大佬请自动跳过。
简单易懂的解法:倒推
回归正题。
这题如果是暴力的话,时间复杂度为 ,肯定是会炸的,于是就可以利用 很小这特殊性质,把时间复杂度跟 扯上关系,于是就想到了倒推。
怎么倒推呢?其实很简单。
先讲明白正序的操作吧
- 如果 ,不妨设当前下标为 :
如果 或者 (既 在操作区间的外面)则不做操作。
反之, 在操作区间的里面,如果 ,则 ,否则 。 - 如果 ,同理,不妨设当前下标为 :
如果 或者 (既 在操作区间的外面)则不做操作。
反之, 在操作区间的里面,由于是对翻转操作,设 的翻转后在 ,则满足一个性质:,所以 。
那再来看看倒序的情况。
首先,记录当前的下标 ,初值 。
从后往前倒序枚举每个操作,计这是第 个操作:
- 如果 :
与正序一样,如果 或者 (既 在操作区间的外面)则不做操作。
反之, 在操作区间的里面,操作即为正序的撤销操作,如果 ,则 ,否则 。 - 如果 :
与正序一样,如果 或者 (既 在操作区间的外面)则不做操作。
反之, 在操作区间的里面,操作其实与正序时一样,由于是对翻转操作,设 的翻转后在 ,。
最后输出 即可。
代码,仅供参考
#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;
}

浙公网安备 33010602011771号