题解:
先算出每一段可能往左往右扩展多少个负数,那么对于负数过于长的一段,它的中间的一部分就被扔掉了。由于每个正数段最多往左右各扩宽自身的长度。所以负数最多只有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;
}