[CF1687C] Sanae and Giant Robot 题解
[CF1687C] Sanae and Giant Robot
并查集?不,这是一道奇妙的转化题。
首先,设 \(c_i=a_i-b_i\),则原题操作转化为:当某个 \([l_i,r_i]\) 满足 \(\sum_{j=l_i}^{r_i}c_j=0\) 时,可以将 \(c_{l_i\sim r_i}\) 清零。目标是让 \(c_i\) 全部清零。
第二步,观察到第一步中的 \(\sum_{j=l_i}^{r_i}c_j\) 是连续子段和的形式,考虑构造前缀和。设 \(s_i=\sum_{j=1}^ic_j\)。则原题操作转化为:当某个 \(s_{l_i-1}=s_{r_i}\) 时,可以将 \(s_{l_i\sim r_i}\) 全部赋值为 \(s_{r_i}\),目标仍是让 \(s_i\) 全部清零。
第三步,注意到因为目标是清零 \(s_i\),所以如果 \(s_{l_i-1}=s_{r_i}\ne0\),操作是不优的,我们只应在 \(s_{l_i-1}=s_{r_i}=0\) 时操作。
现在原题变得很简单了。我们处理出 \(s_i\) 后,每次找一对 \(s_{l_i-1}=s_{r_i}=0\),然后清零 \(s_{l_i\sim r_i}\),直到不能再操作为止。最终若 \(s_i\) 全部清空,则为 YES;反之则为 NO。
具体维护方面,用一个 set 维护所有 \(s_i\ne0\) 的 \(i\),用一个 queue 维护所有 \(s_i=0\) 的 \(i\),用一个 vector 记录下来所有 \(l-1,r\) 的相对关系。从 queue 中取出一个 \(s_i=0\) 的点 \(i\),遍历所有和 \(i\) 相连的点 \(j\),若 \(s_j=0\) 则清空 set 中 \([i,j]\) 的元素,最后检查 set 是否为空即可。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
constexpr int MAXN=2e5+5;
int T,n,m,a[MAXN],b[MAXN];
ll s[MAXN];
vector<int>g[MAXN];
set<int>st;
queue<int>q;
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin>>T;
while(T--){
cin>>n>>m;
st.clear();
q.emplace(0);
for(int i=0;i<=n;++i) g[i].clear();
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i){
cin>>b[i];
s[i]=s[i-1]+a[i]-b[i];
if(s[i]) st.emplace(i);
else q.emplace(i);
}
for(int i=1,u,v;i<=m;++i){
cin>>u>>v;
g[u-1].emplace_back(v);
g[v].emplace_back(u-1);
}
while(!q.empty()){
int u=q.front();
q.pop();
for(auto v:g[u]){
if(s[v]) continue;
int l=min(u,v),r=max(u,v);
for(auto it=st.lower_bound(l);it!=st.end()&&*it<=r;it=st.erase(it))
s[*it]=0,q.emplace(*it);
}
}
cout<<(st.empty()?"YES\n":"NO\n");
}
return 0;
}

浙公网安备 33010602011771号