CF1902D. Robot Queries-二分、思维
link:https://codeforces.com/contest/1902/problem/D
题意:二维平面,一开始在 \((0,0)\) ,有一个由 UDLR
组成的长度为 \(n\) 的移动序列 \(s_1,\dots,s_n\),\(q\) 次询问,每次问:将 \([l,r]\) 翻转后能否经过 \((x,y)\).
\(1\leq n,q\leq 2\times 10^5\).
区间翻转的特性在于,最后到达的位置是不会变的。
假设 \(p_i\) 表示实现了 \([1,i]\) 这些操作后到达的位置,对于 \([0,l-1]\) 和 \([r,n]\) 部分的答案可以直接回答:对每个位置维护一个 vector
表示出现的时间,在上面二分即可。
而对于 \([l,r-1]\) 这一部分,如果能到达 \(p(x,y)\),相当于存在某个序列,使得从原点 \(O\to p_{l-1}\) ,再经过 \(r,r-1,\dots,i\) 的操作到达 \(p\),这等价于经过 \(s_i,\dots,s_r\) 这些操作。
假设 \(v(i,j)\) 表示经过 \([i,j]\) 的操作产生的位移,\(v(i,j)=p_j-p_{i-1}\),则这意味着 \(p_{l-1}+v(i,r)=p\),即 \(p_{l-1}+p_r-p_{i-1}=p\),即查询 \(p_{i-1}=p_{l-1}+p_r-p\),其中 \(l\leq i\leq r\),那么 \(l-1\leq i-1\leq r-1\).
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int N=2e5+5;
typedef pair<int,int> pii;
int n,q;
string s;
pii p[N];
map<pii,vector<int>> order;
int main(){
fastio;
cin>>n>>q>>s;
order[{0,0}].push_back(0);
rep(i,1,n){
p[i].first =p[i-1].first +(s[i-1]=='R')-(s[i-1]=='L');
p[i].second=p[i-1].second+(s[i-1]=='U')-(s[i-1]=='D');
order[p[i]].push_back(i);
}
auto check=[&](pii p,int l,int r){
if(l>r||!order.count(p))return false;
const vector<int> &ve=order[p];
auto itr=lower_bound(ve.begin(),ve.end(),l);
return itr!=ve.end()&&*itr<=r;
};
while(q--){
int x,y,l,r;
cin>>x>>y>>l>>r;
int tx=p[r].first +p[l-1].first -x;
int ty=p[r].second+p[l-1].second-y;
if(check({x,y},0,l-1)||check({x,y},r,n)||check({tx,ty},l-1,r-1))cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}