[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;
}
posted @ 2025-01-14 21:19  Laoshan_PLUS  阅读(23)  评论(0)    收藏  举报