1. 程式人生 > >[bzoj5017][Snoi2017]炸彈 tarjan縮點+線段樹優化建圖+拓撲

[bzoj5017][Snoi2017]炸彈 tarjan縮點+線段樹優化建圖+拓撲

isp stream 現在 aps data fin zoj tput gre

5017: [Snoi2017]炸彈

Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 608 Solved: 190
[Submit][Status][Discuss]

Description

在一條直線上有 N 個炸彈,每個炸彈的坐標是 Xi,爆炸半徑是 Ri,當一個炸彈爆炸時,如果另一個炸彈所在位置 Xj 滿足: Xi?Ri≤Xj≤Xi+Ri,那麽,該炸彈也會被引爆。 現在,請你幫忙計算一下,先把第 i 個炸彈引爆,將引爆多少個炸彈呢?

Input

第一行,一個數字 N,表示炸彈個數。 第 2~N+1行,每行 2 個數字,表示 Xi,Ri,保證 Xi 嚴格遞增。 N≤500000 ?10^18≤Xi≤10^18 0≤Ri≤2×10^18

Output

一個數字,表示Sigma(i*炸彈i能引爆的炸彈個數),1<=i<=N mod10^9+7。

Sample Input

4
1 1
5 1
6 5
15 15

Sample Output

32


HINT

Source

顯然一個點可以引爆的炸彈是一個連續的區間,對於每一個點我們向他可以引爆的最左邊的炸彈到最右邊的炸彈連邊。可以使用線段樹優化建圖。 我們對建出來的圖tarjan縮點,每個點維護minl和maxr。 對於這個圖按拓撲序倒序dp,求出每個點的minl和maxr,統計答案即可。 技術分享圖片
  1 #include<iostream>
  2
#include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<cstdio> 6 #include<algorithm> 7 #define maxn 500005 8 #define ll long long 9 #define mod 1000000007 10 using namespace std; 11 inline ll read() { 12 char ch=getchar();ll x=0,f=1; 13 for(;!isdigit(ch);ch=getchar()) if
(ch==-) f=-1; 14 for(;isdigit(ch);ch=getchar()) x=x*10+ch-0; 15 return x*f; 16 } 17 int n,rt; 18 ll s[maxn*5],a[maxn*5],id[maxn*5],tsz; 19 struct seg {int s[2];ll mn,mx;}t[maxn*5]; 20 struct Edge {int fr,to,nxt;}e[maxn*20]; 21 int head[maxn*5],sz; 22 void addedge(int u,int v) {e[sz].fr=u;e[sz].nxt=head[u];e[sz].to=v;head[u]=sz++;} 23 void build(int l,int r,int &x) { 24 x=++tsz; 25 if(l==r) {id[l]=x;t[x].mn=t[x].mx=l;return;} 26 int mid=l+r>>1; 27 build(l,mid,t[x].s[0]);build(mid+1,r,t[x].s[1]); 28 if(t[x].s[0]) addedge(x,t[x].s[0]); 29 if(t[x].s[1]) addedge(x,t[x].s[1]); 30 t[x].mn=l;t[x].mx=r; 31 return ; 32 } 33 void add(int l,int r,int x,int L,int R,int p) { 34 if(L<=l&&R>=r) {if(id[p]==x) return;addedge(id[p],x);return;} 35 int mid=l+r>>1; 36 if(L<=mid) add(l,mid,t[x].s[0],L,R,p); 37 if(R>mid) add(mid+1,r,t[x].s[1],L,R,p); 38 return; 39 } 40 bool inq[maxn*5]; 41 ll dfn[maxn*5],low[maxn*5],tim,q[maxn*5],top,lm[maxn*5],rm[maxn*5]; 42 int bel[maxn*5],scc; 43 void tarjan(int x) { 44 dfn[x]=low[x]=++tim;q[++top]=x;inq[x]=1; 45 for(int i=head[x];i>=0;i=e[i].nxt) { 46 int to=e[i].to; 47 if(!dfn[to]){ 48 tarjan(to);low[x]=min(low[x],low[to]); 49 }else if(inq[to]) low[x]=min(low[x],dfn[to]); 50 } 51 if(dfn[x]==low[x]) { 52 scc++; 53 lm[scc]=214748364700000000ll; 54 ll now; 55 do { 56 now=q[top--];inq[now]=0;bel[now]=scc; 57 lm[scc]=min(lm[scc],t[now].mn);rm[scc]=max(rm[scc],t[now].mx); 58 }while(now!=x); 59 } 60 } 61 ll rd[maxn*5]; 62 int main() { 63 //freopen("bomb9.in","r",stdin); 64 memset(head,-1,sizeof(head)); 65 n=read(); 66 for(int i=1;i<=n;i++) {s[i]=read();a[i]=read();} 67 build(1,n,rt); 68 for(int i=1;i<=n;i++) { 69 int now=lower_bound(s+1,s+n+1,s[i])-s,L=lower_bound(s+1,s+n+1,s[i]-a[i])-s,R=upper_bound(s+1,s+n+1,s[i]+a[i])-s-1; 70 if(L==R) continue;add(1,n,1,L,R,i); 71 } 72 for(int i=1;i<=tsz;i++) if(!dfn[i]) {tarjan(i);} 73 int tmp=sz;sz=0;memset(head,-1,sizeof(head)); 74 for(int i=0;i<tmp;i++) { 75 int u=bel[e[i].fr],v=bel[e[i].to]; 76 if(u==v) continue; 77 rd[v]++;addedge(u,v); 78 } 79 int hd=0,tl=0; 80 for(int i=1;i<=scc;i++) if(!rd[i]) q[tl++]=i; 81 while(hd!=tl) { 82 int now=q[hd++]; 83 for(int i=head[now];i>=0;i=e[i].nxt) { 84 int to=e[i].to;rd[to]--; 85 if(!rd[to]) q[tl++]=to; 86 } 87 } 88 for(int i=scc;i>=1;i--) { 89 int now=q[i]; 90 for(int j=head[now];j>=0;j=e[j].nxt) { 91 int to=e[j].to; 92 lm[now]=min(lm[now],lm[to]);rm[now]=max(rm[now],rm[to]); 93 } 94 } 95 ll ans=0; 96 for(int i=1;i<=n;i++) { 97 ans+=(ll)i*(rm[bel[id[i]]]-lm[bel[id[i]]]+1);ans%=mod; 98 } 99 printf("%lld\n",ans); 100 } 101
View Code

[bzoj5017][Snoi2017]炸彈 tarjan縮點+線段樹優化建圖+拓撲