2019牛客暑期多校训练营(第二场)J Subarray

题解:

        先算出每一段可能往左往右扩展多少个负数,那么对于负数过于长的一段,它的中间的一部分就被扔掉了。由于每个正数段最多往左右各扩宽自身的长度。所以负数最多只有2e7个。

        接下来可以用树状数组统计,但是这样会多一个log。因为每次询问相较于上次只移动了一个单位所以直接统计在上次询问的基础上更改就好。代码挺短的......

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 1e9-1;
const int maxn = 1e7+5;
const int st = 2e7+1;
int n,L[maxn],R[maxn],exl[maxn],exr[maxn];
int f[maxn*3];
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    ios::sync_with_stdio(0);
    cin>>n;
    for(int i = 1; i <= n; i++){
        cin>>L[i]>>R[i];
    }

    L[n+1] = INF+1; R[n+1] = INF+1; L[0] = -1; R[0] = -1;

    int s = R[1]-L[1]+1;
    for(int i = 1; i <= n; i++){
        exr[i] = min(s,L[i+1]-R[i]-1);
        s -= (L[i+1]-R[i]-1);
        if(s < 0) s = 0;
        s += (R[i+1]-L[i+1]+1);
    }

    s = R[n]-L[n]+1;
    for(int i = n; i >= 1; i--){
        exl[i] = min(s, L[i]-R[i-1]-1);
        s -= (L[i]-R[i-1]-1);
        if(s < 0) s = 0;
        s += (R[i-1]-L[i-1]+1);
    }

    int last = 0;
    s = st; f[s] = 1;
    LL sum = 1, ans = 0;
    for(int i = 1; i <= n; i++){
        for(int j = max(last,L[i]-exl[i]); j <= R[i]+exr[i]; j++){
            int add = -1;
            if(j >= L[i] && j <= R[i]) add = 1;
            s += add;
            ++f[s];
            if(add == -1) sum -= f[s+1] - 1;
            else sum += f[s];
            ans += sum - f[s];
        }
        last = R[i]+exr[i]+1;
    }
    cout<<ans<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值