CF1887C Minimum Array

题目


结论:记 a , b a,b a,b 是两个序列, a ′ , b ′ a',b' a,b 分别是 a , b a,b a,b 的差分,那么 a > b ⟺ a ′ > b ′ a>b\Longleftrightarrow a'>b' a>ba>b。充分性:找到 a , b a,b a,b 第一个不相同的位置 i i i,有 a i > b i , a i − 1 = b i − 1 a_i>b_i,a_{i-1}=b_{i-1} ai>bi,ai1=bi1,显然结论成立;必要性,找到 a ′ , b ′ a',b' a,b 第一个不相同的位置 j j j,有 a j ′ > b j ′ , a j − 1 ′ = b j − 1 ′ a'_j>b'_j,a'_{j-1}=b'_{j-1} aj>bj,aj1=bj1,加前缀和后显然结论成立。

对于此题,考虑差分,那么区间修改就变成两点修改,而这并不会改变原序列的相对字典序大小。容易发现若差分数组的第一个非零的数小于零,则字典序变小,当前的原数组是最小的,为了方便,此时可将差分数组清空(因为我们要的是相对字典序大小),继续后面的操作。用 set 维护差分数组的非零数。

时间复杂度 O ( n + ( ∑ q ) log ⁡ ( ∑ q ) ) O(n+(\sum q)\log(\sum q)) O(n+(q)log(q))

#include
using namespace std;
#define ll long long
#define int long long
const int N=5e5+10;
int n,q,l[N],r[N];
ll x[N],cf[N],a[N],cf1[N];
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    cin>>q;
    set<int> s;
    int pos=0;
    for(int i=1;i<=q;i++){
        cin>>l[i]>>r[i]>>x[i];
        cf[l[i]]+=x[i],cf[r[i]+1]-=x[i];
        if(cf[l[i]]) s.insert(l[i]);
        else if(s.count(l[i])) s.erase(l[i]);
        if(cf[r[i]+1]) s.insert(r[i]+1);
        else if(s.count(r[i]+1)) s.erase(r[i]+1);
        if(s.size()&&cf[*s.begin()]<0){
            pos=i;
            for(auto j:s) cf[j]=0;
            s.clear();
        }
    }
    for(auto j:s) cf[j]=0;
    for(int i=1;i<=pos;i++) cf[l[i]]+=x[i],cf[r[i]+1]-=x[i];
    for(int i=1;i<=n;i++) cf1[i]=cf1[i-1]+cf[i],cout<<a[i]+cf1[i]<<' ';
    for(int i=1;i<=pos;i++) cf[l[i]]-=x[i],cf[r[i]+1]+=x[i];
    cout<<"\n";
}
signed main()
{
    cin.tie(0)->sync_with_stdio(0);
    int T;
    cin>>T;
    while(T--) solve();
}

你可能感兴趣的:(c++,算法,开发语言)