CF1687C Sanae and Giant Robot 分析
题目概述
给定长度为 \(n\) 的 \(a,b\),给定 \(m\) 个区间 \(l,r\),如果 \(\sum_{i=l}^r a_i=\sum_{i=l}^r b_i\),那么就令这个区间的 \(a_i=b_i\)。
问能否将所有的 \(a\) 变成 \(b\)。
分析
转化一下不难想到令 \(a_i-=b_i\),然后再对 \(a\) 作前缀和。
对于一个可以改变的区间,一定满足 \(sum_{l_i-1}=sum_{r_i}=0\)。
暴力枚举是 \(\mathcal{O}(n^2m)\) 的。
我们可以考虑用 bfs 进行优化,每次对于一个左端点进行扩张,扩张到的新的点加入队列。
然后为了每个点只进行一次,所以我们用 \(set\) 维护我们还剩下哪些没有扩张。
最后看 \(set\) 是否为空即可。
代码
\(\amthcal{O}(n\log n)\)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#define int long long
#define N 200005
using namespace std;
int T,n,m,a[N],b[N],du[N];
vector<int> e[N];
signed main(){
cin >> T;
for (;T--;) {
scanf("%lld%lld",&n,&m);
e[0].clear();
for (int i = 1;i <= n;i ++) scanf("%lld",&a[i]),e[i].clear();
for (int i = 1;i <= n;i ++) scanf("%lld",&b[i]),a[i] -= b[i];
for (int i = 1;i <= n;i ++) a[i] += a[i - 1];
vector<pair<int,int> >p;
p.resize(m + 1);
for (int i = 1;i <= m;i ++) {
int l,r;
scanf("%lld%lld",&l,&r);
p[i] = {l,r};
e[l - 1].push_back(i);
e[r].push_back(i);
du[i] = 2;
}
set<int> st;
for (int i = 0;i <= n;i ++) st.insert(i);
queue<int> q;
for (int i = 0;i <= n;i ++)
if (a[i] == 0) q.push(i),st.erase(i);
while(!q.empty()) {
int t = q.front();
q.pop();
for (auto i : e[t])
if ((--du[i]) == 0) {
int l = p[i].first,r = p[i].second;
auto lt = st.lower_bound(l),rt = st.upper_bound(r);
for (auto it = lt;it != rt;it ++) q.push(*it);
st.erase(lt,rt);
}
}
puts(st.size() ? "NO" : "YES");
}
return 0;
}

浙公网安备 33010602011771号