题意:给你一个n 表示有n段连续的1序列 现在问你 在总长度为0~1e9-1的范围内有多少个大于0的子段
思路:假设我们统计了当前的前缀和 我们显然可以用树状数组维护一下前缀和 这样我们可以nlogn算出答案 但是对于1e7的数据 这样处理肯定会超时 所以我们考虑前缀和是一个每次变化都是1的折线
我们可以直接数组模拟lazy来求出答案
#include <bits/stdc++.h> using namespace std; const int N = 1e7+7; const int inf = 0x3f3f3f3f; typedef long long ll; const ll mod = 1e7+9; int l[N],r[N]; int f[N],g[N],sum[3*N]; int b[3*N],c[3*N]; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin>>n; for(int i=1;i<=n;i++){ cin>>l[i]>>r[i]; } f[1]=r[1]-l[1]+1; for(int i=2;i<=n;i++) f[i]=max(r[i]-l[i]+1,f[i-1]-(l[i]-r[i-1]-1)+r[i]-l[i]+1); g[n]=r[n]-l[n]+1; for(int i=n-1;i>=1;i--) g[i]=max(r[i]-l[i]+1,g[i+1]-(l[i+1]-r[i]-1)+r[i]-l[i]+1); int i=1; int now=1e7; ll ans=0; while(i<=n){ int j=i+1; while(j<=n&&g[j]+f[j-1]>=(l[j]-r[j-1]-1)){ j++; } j--; int le=max(0,l[i]-g[i]); int ri=min(int(1e9)-1,r[j]+f[j]); int t=i; int mx,mi; mx=-1; mi=inf; for(int k=le;k<=ri;k++){ if(k>=l[t]&&k<=r[t]) sum[k-le+1]=sum[k-le]+1; else sum[k-le+1]=sum[k-le]-1; if(k==r[t]) t++; mx=max(mx,sum[k-le+1]+now); mi=min(mi,sum[k-le+1]+now); b[sum[k-le+1]+now]++; } for(int k=mx-1;k>=mi;k--) b[k]+=b[k+1]; ans+=b[now+1]; for(int k=le;k<=ri;k++){ t=sum[k-le+1]+now; b[t+1]-=c[t+1]; c[t]+=c[t+1]+1; c[t+1]=0; ans+=b[t+1]; } for(int k=mi;k<=mx;k++) b[k]=0,c[k]=0; i=j+1; } cout<<ans<<endl; }