直接线段树维护[l,r]的点能炸到的左端点和右端点,反着跑7次洛谷loj全过???
#include<bits/stdc++.h>
#define int long long
#define maxn 500005
using namespace std;
int n,x[maxn],ran[maxn],l[maxn],r[maxn],maxx,ans;
struct seg{int lef,rig;}tree[maxn*6];
seg operator + (const seg &aaa,const seg &bbb){return (seg){min(aaa.lef,bbb.lef),max(aaa.rig,bbb.rig)};}
void build(int id,int l,int r){
maxx=max(maxx,id);
tree[id].lef=l;tree[id].rig=r;
if(l==r)return;
int mid=l+r>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
return;
}
void pushup(int rt){
if(rt*2<=maxx)tree[rt].lef=min(tree[rt].lef,tree[rt<<1].lef),tree[rt].rig=max(tree[rt].rig,tree[rt<<1].rig);
if(rt*2+1<=maxx)tree[rt].lef=min(tree[rt].lef,tree[rt<<1|1].lef),tree[rt].rig=max(tree[rt].rig,tree[rt<<1|1].rig);
return;
}
void modify(int id,int l,int r,int place,int upl,int upr){
if(l==r&&l==place){
tree[id].lef=min(tree[id].lef,upl);
tree[id].rig=max(tree[id].rig,upr);
return;
}
int mid=l+r>>1;
if(place<=mid)modify(id<<1,l,mid,place,upl,upr);
else modify(id<<1|1,mid+1,r,place,upl,upr);
pushup(id);return;
}
seg query(int id,int l,int r,int tol,int tor){
if(r<tol||l>tor)return (seg){500000,0};
if(tol<=l&&r<=tor)return tree[id];
int mid=l+r>>1;
return query(id<<1,l,mid,tol,tor)+query(id<<1|1,mid+1,r,tol,tor);
}
int p[maxn];
void AC(){
random_shuffle(p+1,p+1+n);
return;
}
signed main(){
cin>>n;for(int i=1;i<=n;++i)cin>>x[i]>>ran[i],l[i]=r[i]=p[i]=i;
build(1,1,n);
for(int totot=1;totot<=7;++totot){
// AC();
for(int i=n;i>=1;--i){
int res=i;i=p[i];
int L=i,R=n,mid,idr=i,idl=i;
while(L<=R){
mid=L+R>>1;
if(x[mid]<=x[i]+ran[i])idr=mid,L=mid+1;
else R=mid-1;
}
L=1;R=i;
while(L<=R){
mid=L+R>>1;
if(x[mid]>=x[i]-ran[i])idl=mid,R=mid-1;
else L=mid+1;
}
seg point=query(1,1,n,idl,idr);
l[i]=point.lef;r[i]=point.rig;
modify(1,1,n,i,l[i],r[i]);
i=res;
}
}
for(int i=1;i<=n;++i)
(ans+=i*(r[i]-l[i]+1))%=(1000000007);
cout<<ans;
return 0;
}