题解:每个炸弹爆炸影响一个区间,通过二分查找找到
若A爆炸炸到B则连一条A到B的边
线段树优化建图
缩点+DP
因为每个炸弹的答案一定是一个区间,所以记录每个节点的左端点和右端点
合并时取最值
反思:思维定式,以为求解可达点个数不能合并
/************************************************************** Problem: 5017 User: ws_zzyer Language: C++ Result: Accepted Time:5928 ms Memory:390956 kb ****************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #define lo now<<1 #define ro now<<1|1 using namespace std; const int maxn=1600000; const int oo=1000000000; const int mm=1000000007; int n,totn; long long a[maxn]; long long r[maxn]; int tl[maxn],tr[maxn]; int cntedge; int head[maxn]; int to[30000009],nex[30000009]; void Addedge(int x,int y){ nex[++cntedge]=head[x]; to[cntedge]=y; head[x]=cntedge; } struct SegmentTree{ int l,r; int u; }tree[500009<<2]; void BuildTree(int now,int l,int r){ tree[now].l=l;tree[now].r=r; tree[now].u=++totn; for(int i=l;i<=r;++i)Addedge(totn,i); if(l==r)return; int mid=(l+r)>>1; BuildTree(lo,l,mid); BuildTree(ro,mid+1,r); } void Updatasec(int now,int ll,int rr,int x){ if(tree[now].l>=ll&&tree[now].r<=rr){ Addedge(x,tree[now].u); return; } int mid=(tree[now].l+tree[now].r)>>1; if(ll<=mid)Updatasec(lo,ll,rr,x); if(rr>mid)Updatasec(ro,ll,rr,x); } int dfsclock,scccnt; int pre[maxn],lowlink[maxn],sccno[maxn]; int lb[maxn],rb[maxn]; int S[maxn],top; void Dfs(int u){ pre[u]=lowlink[u]=++dfsclock; S[++top]=u; for(int i=head[u];i;i=nex[i]){ int v=to[i]; if(!pre[v]){ Dfs(v); lowlink[u]=min(lowlink[u],lowlink[v]); }else if(!sccno[v]){ lowlink[u]=min(lowlink[u],pre[v]); } } if(lowlink[u]==pre[u]){ ++scccnt; for(;;){ int x=S[top--]; sccno[x]=scccnt; if(x==u)break; } } } vector<int>G[maxn]; void Tarjan(){ for(int i=1;i<=totn;++i)if(!pre[i])Dfs(i); for(int i=1;i<=totn;++i){ lb[i]=oo;rb[i]=-oo; } for(int i=1;i<=n;++i){ int x=sccno[i]; lb[x]=min(lb[x],tl[i]); rb[x]=max(rb[x],tr[i]); } for(int u=1;u<=totn;++u){ for(int i=head[u];i;i=nex[i]){ int v=to[i]; if(sccno[u]!=sccno[v]){ G[sccno[u]].push_back(sccno[v]); } } } } int vis[maxn]; void Dp(int x){ if(vis[x])return; vis[x]=1; for(int i=0;i<G[x].size();++i){ int v=G[x][i]; Dp(v); lb[x]=min(lb[x],lb[v]); rb[x]=max(rb[x],rb[v]); } } int main(){ scanf("%d",&n);totn=n; for(int i=1;i<=n;++i){ scanf("%lld%lld",&a[i],&r[i]); } BuildTree(1,1,n); for(int i=1;i<=n;++i){ tl[i]=lower_bound(a+1,a+1+n,a[i]-r[i])-a; tr[i]=upper_bound(a+1,a+1+n,a[i]+r[i])-a-1; // cout<<tl[i]<<‘ ‘<<tr[i]<<endl; Updatasec(1,tl[i],tr[i],i); } Tarjan(); for(int i=1;i<=totn;++i)if(!vis[i])Dp(i); long long ans=0; for(int i=1;i<=n;++i){ // cout<<rb[sccno[i]]-lb[sccno[i]]<<endl; ans=(ans+1LL*(1+rb[sccno[i]]-lb[sccno[i]])*i)%mm; } printf("%lld\n",ans); return 0; }