(CF1902D)我个人认为STL是个【】

· · 题解

前言

STL。虽然但是比大数据结构强喵。

题意

有一个无限的平面直角坐标系。最初,机器人站在点 (0,0)。机器人可以执行上下左右四种指令。给定指令序列,每次询问要求翻转指令序列的某个指定子串,问是否经过指定点。

思路

我们考虑把上下左右分别看成 ({\color{red}0},{\color{blue}+1}),({\color{red}0},{\color{blue}-1}),({\color{red}-1},{\color{blue}0}),({\color{red}+1},{\color{blue}0})。我们设映射下来的数组分别为 {\color{red}a} 数组和 {\color{blue}b} 数组,那么这两个数组的前缀和构成的每一个数对就是在不翻转的情况下机器人所能到的 ({\color{red}x},{\color{blue}y})

现在我们考虑翻转,那么我们就要考虑翻转后的前缀和,也就是考虑后缀和。我们以横坐标 {\color{red}x} 为例,设 {\color{red}a} 的前缀和数组为 {\color{red}f},后缀和数组为 {\color{red}g}。我们考虑翻转区间 [l,r] 对 前缀和数组的影响。

我们发现,翻转区间 [l,r],对 [1,l-1][r+1,n] 的前缀和是没有影响的,所以我们只考虑翻转区间 [l,r][l,r] 的前缀和的影响。我们先考虑特殊情况,再考虑一般情况:

所以当 i\in [l,r] 时,f'_{i}=g_{r-i+l}-g_{r+1}+f_{l-1}

当然 \color{blue}b 数组前后缀的翻转方式与此相同。

那么我们如果要在 f' 数组里找一个数 X 时,我们分两种情况讨论:

当然如果我们要找的是一个数对 ({\color{red}X},{\color{blue}Y}) 也可以用同样的方法解决,把 map 开成 map<pair<int,int>,int> 就好了。

提示

依照现在的思路是过不了的,因为可能有两个点相同,也就是 map 可能会被重复赋值。

那么我们就可以开 vector 记录与 map 存储的点相同的点,在里面二分即可。对于 (X,Y) 不在 [l,r] 内的情况,我们也可以记录下标最大的点和最小的点。

代码

:::success[在这里喵]

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=5e5+5;
map<PII,int> mp;
map<PII,int> mp2;
map<PII,int> mp3;
int a[N],f[N],g[N];
int b[N],p[N],q[N];
vector<int> v[N];
string s;
int n,Q;
void man(){
    int x,y,l,r;
    cin>>x>>y>>l>>r;
    if(x==0&&y==0){
        cout<<"YES\n";
        return;
    }
    int k=mp2[{x,y}];
    if(k>r){
        cout<<"YES\n";
        return;
    }
    k=mp3[{x,y}];
    if(k&&k<l){
        cout<<"YES\n";
        return;
    }
    x-=f[l-1];
    y-=p[l-1];
    x+=g[r+1];
    y+=q[r+1];
    k=mp[{x,y}];
    auto it=lower_bound(v[k].begin(),v[k].end(),l);
    if(it==v[k].end()||*it>r) cout<<"NO\n";
    else cout<<"YES\n";
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>n>>Q;
    cin>>s;
    for(int i=1;i<=n;i++){
        if(s[i-1]=='R') a[i]=1;
        else if(s[i-1]=='L') a[i]=-1;
        else if(s[i-1]=='U') b[i]=1;
        else if(s[i-1]=='D') b[i]=-1;
        f[i]=f[i-1]+a[i];
        p[i]=p[i-1]+b[i];
        mp2[{f[i],p[i]}]=i;
    }
    for(int i=n;i>=1;i--){
        g[i]=g[i+1]+a[i];
        q[i]=q[i+1]+b[i];
        mp3[{f[i],p[i]}]=i;
    }
    for(int i=1;i<=n;i++){
        auto tmp=make_pair(g[i],q[i]);
        if(mp[tmp]==0) mp[tmp]=i;
        v[mp[tmp]].push_back(i);
    }
    while(Q--) man();
    return 0;
}

:::

后记

都看到这里了喵,点个赞好不好喵~