牛客网 Subarray 【思维】

题意:有个区间[1, 1e9], 给你n个被1覆盖的区间,剩下的都是-1,问你有多少个区间和大于0。

思路:能被1覆盖的区间长度最多有3e7, 因为区间向前,向后最多可以覆盖1e7,所以加起来就是3e7,这是本题求解的关键。

所以我们可以处理一下区间,让它尽可能的延伸而又不至于小于0,这样我们就可以用树状数组来求,可范围太大了我们只能用别的方法。我们需要计算在当前点有多少前面点的前缀和大于等于它就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls rt << 1
#define rs rt << 1|1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1|1
const int maxn = 1e7 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
int l[maxn], r[maxn];
int L[maxn], R[maxn];
int cnt[maxn * 2];

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d%d", &l[i], &r[i]);
    l[n + 1] = 1e9, r[0] = -1;
    int sum1 = 0;
    for(int i = 1; i <= n; ++i) //每个区间右端点最远可以影响 
    {
        int m1 = l[i] - r[i - 1] - 1;
        sum1 = max(sum1 - m1, 0) + r[i] - l[i] + 1;
        R[i] = min(r[i] + sum1, l[i + 1] - 1);
    }
    sum1 = 0;
    for(int i = n; i; --i) //每个区间左端点最远往左可以影响 
    {
        int m1 = l[i + 1] - r[i] - 1;
        sum1 = max(sum1 - m1, 0) + r[i] - l[i] + 1;
        L[i] = max(l[i] - sum1, r[i - 1] + 1);
    }
    int id = 1e7, last = -1;
    ll tmp = 0, ans = 0;
    for(int i = 1; i <= n; ++i)
    {
        for(int j = max(last, L[i]); j <= R[i]; ++j)
        {
            if(l[i] <= j && j <= r[i]) //如果在原本区间中 
            {
                ++cnt[id];
                tmp += cnt[id];
                --id;
            }
            else
            {
                ++cnt[id];
                ++id;
                tmp -= cnt[id];
            }
            ans += tmp;
        }
        last = R[i] + 1;
    }
    printf("%lld\n", ans);
    return 0;
}

 

#pragma GCC optimize(3)
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define ALL(x) (x).begin(),(x).end()
#define mem(x,y) memset((x),(y),sizeof(x))
#define SZ(x) ((int)(x).size())
#define P2(x) ((x)*(x))
#define P pair<int,int> 
using namespace std;
typedef long long ll;
const int maxn = 3e7+10;
const int maxm = 2e5 + 10;
const int mod = 1e9 + 7;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int inf = 1000000000;
const double eps = 1e-6;
//lowbit---------------------------------------------------------------------
int LobN;//定义长度
inline int lowbit(int x){ return (x&(-x)); }
void add(ll*c, int x, ll v){ while (x <= LobN)c[x] += v, x += lowbit(x); }
ll que(ll*c, int x){ ll res = 0; while (x)res += c[x], x -= lowbit(x); return res; }
//----------------------------------------------------------------------------
template<typename S, typename T> inline bool Min(S &a, const T &b){ return a > b ? a = b, true : false; }
template<typename S, typename T> inline bool Max(S &a, const T &b){ return a < b ? a = b, true : false; }
template<typename S, typename T> inline void Adm(S &a, const T &b){ a = (a + b) % mod; if (a < 0) a += mod; }
template<typename S, typename T> inline void Mum(S &a, const T &b){ a = 1LL * a * b % mod; }
template<typename T> inline T Gcd(T a, T b){ while (b){ T t = b; b = a % b; a = t; }return a; }
template<typename T> inline int BitCnt(T x){ int cnt = 0; while (x)++cnt, x &= x - 1; return cnt; }
template<typename T> inline bool IsPri(T x) { if (x < 2) return false; for (T i = 2; i * i <= x; ++i) if (x % i == 0) return false; return true; }
inline ll qpow(ll a, ll n){ ll t = 1; while (n){ if (n & 1)t = t * a % mod; a = a * a % mod, n >>= 1; }return t; }
const int N = 1e7+10;
int l[maxn], r[maxn];
int L[maxn], R[maxn];
ll d[maxn + N], dd[maxn + N];
int main(){
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        scanf("%d%d", &l[i], &r[i]);
    }
    l[n + 1] = inf, r[0] = -inf;
    int j = 1;
    ll ans = 0;
    int s = r[1] - l[1] + 1;
    for (int i = 1; i <= n; i++){
        R[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--){
        L[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;
    dd[0+N] = d[0+N] = 1;
    ll ss = 0;
    ll snm = 1;
    for (int i = 1; i <= n; i++){
        int ad = 1;
        for (int j = max(last,l[i]-L[i]); j <= r[i] + R[i]; j++){
            if (j >= l[i] && j <= r[i])ad = 1;
            else ad = -1;
            ss += ad;
            d[ss+N]++;
             
            if (ad == 1)//上升,直接加
            {
                ans += snm;
                snm += d[ss + N];
            }
            else {//下降,把大于以及自身的删掉
                snm++;
                snm -= d[ss + 1+N];
                ans += snm-(d[ss+N]);
            }
        }
        last = r[i] + R[i]+1;
    }
    cout << ans << endl;
 
    return 0;
}
/*
2
5 9
12 17
 
3
3 5
6 6
7 9
 
3
3 5
8 8
9 10
 
1
999999998 999999999
 
200
 
76
 
49
 
4
*/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值