线段树优化建图,再跑$tarjan$已成$DAG$,然后反跑拓扑排序即可,因为最小的反倒是连边连的最多的地方,即使方向两边入读为$0$的点,然后在随便跑个计数$dp$即可
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define mod 1000000007 using namespace std; queue<long long> que; inline long long read() { long long f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } long long n,r[500001],p[500001],ll[500001],rr[500001],m; long long query_l(long long pos,long long rrr){ long long l=1,r=n,minn=2<<30-1,mid,ls=pos-rrr; while(l<=r){ mid=l+r>>1; if(p[mid]>=ls) minn=min(minn,mid),r=mid-1; else l=mid+1; }return minn; } long long query_r(long long pos,long long rrr){ long long l=1,r=n,maxn=0,mid,lr=pos+rrr; while(l<=r){ mid=l+r>>1; if(p[mid]<=lr) maxn=max(maxn,mid),l=mid+1; else r=mid-1; }return maxn; } struct node{ long long u,v,nex; }x[10999999]; long long head[9500001],vis[9500001],cnt,f[9500001],uu[10999999],vv[10999999]; struct node1{ long long u,v; }s[10999999]; void add(long long u,long long v){ x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++; s[cnt].u=u,s[cnt].v=v; } void build(long long k,long long l,long long r){ if(l==r) {add(k+n,l);return;} long long mid=l+r>>1; build(k<<1,l,mid),build(k<<1|1,mid+1,r); add(k+n,(k<<1)+n),add(k+n,(k<<1|1)+n); return; } void query(long long k,long long l,long long r,long long x,long long y,long long st){ if(x<=l&&r<=y){add(st,k+n);return;} long long mid=l+r>>1; if(x<=mid) query(k<<1,l,mid,x,y,st); if(mid<y) query(k<<1|1,mid+1,r,x,y,st); return; } long long du[10999999],co[10999999],col,ans[10999999],low[10999999],dfn[10999999],sta[10999999],tot,num; void tarjan(long long xx){ low[xx]=dfn[xx]=++num; sta[++tot]=xx; for(long long i=head[xx];i!=-1;i=x[i].nex){ long long v=x[i].v; if(!dfn[v]) {tarjan(v);low[xx]=min(low[xx],low[v]);} else if(!co[v]) low[xx]=min(low[xx],dfn[v]); } if(dfn[xx]==low[xx]){ co[xx]=++col; if(xx>=1&&xx<=n) ans[col]++; while(sta[tot]!=xx){ co[sta[tot]]=col; if(sta[tot]>=1&&sta[tot]<=n) ans[col]++; tot--; }tot--; }return; } long long dp[19999999]; bool cmp(node1 x1,node1 x2){ if(x1.u==x2.u) return x1.v<x2.v; return x1.u<x2.u; } void reset(){ for(long long i=1;i<=cnt;i++) s[i].u=co[s[i].u],s[i].v=co[s[i].v]; sort(s+1,s+cnt+1,cmp); m=cnt; memset(head,-1,sizeof(head)),cnt=0; for(long long i=1;i<=m;i++){ if(((s[i].u!=s[i].v)&&((s[i].u!=s[i-1].u)||(s[i].v!=s[i-1].v)))) { add(s[i].v,s[i].u),du[s[i].u]++; } } for(long long i=1;i<=col;i++) dp[i]=ans[i]; for(long long i=1;i<=col;i++){ if(!du[i]) que.push(i); } } void topu(){ while(!que.empty()){ long long u=que.front();que.pop(); for(long long i=head[u];i!=-1;i=x[i].nex){ dp[x[i].v]+=dp[u]; du[x[i].v]--; if(!du[x[i].v]) que.push(x[i].v); } } } long long sum; int main() { memset(head,-1,sizeof(head)); n=read(); for(long long i=1;i<=n;i++) p[i]=read(),r[i]=read(); for(long long i=1;i<=n;i++){ ll[i]=query_l(p[i],r[i]),rr[i]=query_r(p[i],r[i]); } build(1,1,n); for(long long i=1;i<=n;i++) query(1,1,n,ll[i],rr[i],i); for(long long i=1;i<=n;i++) if(!dfn[i]) tarjan(i); reset(); topu(); for(long long i=1;i<=n;i++) sum+=i*dp[co[i]],sum%=mod; cout<<sum; }