把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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;
}
posted @ 2025-10-29 20:37  high_skyy  阅读(3)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end