[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;
}