BZOJ5017 炸弹(线段树优化建图+Tarjan+拓扑)
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。
题解
因为每一个炸弹爆炸后引爆的是一个区间的炸弹,所以想到线段树优化建图。
然后可能有环所以跑Tarjan求强连通分量。最后拓扑合并答案。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 const int N=500010; 9 const int mod=1e9+7; 10 queue<int> q; 11 int cnt,cnt1,head[N*4],head1[N*4]; 12 int num,id[N*4],di[N*4]; 13 int dfn[N*4],low[N*4],tot1,top,stack[N*4],book[N*4],num1,col[N*4],tmp; 14 long long a[N],r[N],b[N],maxx[N*4],minn[N*4]; 15 int n,tot,in[N*4]; 16 long long ans; 17 struct tree{ 18 int l,r; 19 }tr[N*4]; 20 struct edge{ 21 int to,nxt,u; 22 }e[N*20],e1[N*20]; 23 void add(int u,int v){ 24 cnt++; 25 e[cnt].nxt=head[u]; 26 e[cnt].u=u; 27 e[cnt].to=v; 28 head[u]=cnt; 29 } 30 void add1(int u,int v){ 31 cnt1++; 32 e1[cnt1].nxt=head1[u]; 33 e1[cnt1].to=v; 34 head1[u]=cnt1; 35 } 36 void build(int l,int r,int now){ 37 num=max(num,now); 38 tr[now].l=l;tr[now].r=r; 39 if(r==l){ 40 id[l]=now; 41 di[now]=l; 42 return; 43 } 44 int mid=(tr[now].l+tr[now].r)>>1; 45 build(l,mid,now*2); 46 build(mid+1,r,now*2+1); 47 add(now,now*2); 48 add(now,now*2+1); 49 } 50 void update(int l,int r,int now,int u){ 51 if(tr[now].l==l&&tr[now].r==r){ 52 add(u,now); 53 return; 54 } 55 int mid=(tr[now].l+tr[now].r)>>1; 56 if(l>mid)update(l,r,now*2+1,u); 57 else if(r<=mid)update(l,r,now*2,u); 58 else{ 59 update(l,mid,now*2,u); 60 update(mid+1,r,now*2+1,u); 61 } 62 } 63 void Tarjan(int u){ 64 dfn[u]=low[u]=++tot1; 65 stack[++top]=u; 66 book[u]=1; 67 for(int i=head[u];i;i=e[i].nxt){ 68 int v=e[i].to; 69 if(dfn[v]==0){ 70 Tarjan(v); 71 low[u]=min(low[u],low[v]); 72 } 73 else if(book[v])low[u]=min(low[u],dfn[v]); 74 } 75 if(dfn[u]==low[u]){ 76 int x; 77 num1++; 78 minn[num1]=4e18; 79 maxx[num1]=-4e18; 80 bool flag=false; 81 do{ 82 x=stack[top--]; 83 book[x]=0; 84 col[x]=num1; 85 if(di[x]){ 86 if(!flag){ 87 minn[num1]=a[di[x]]-r[di[x]]; 88 maxx[num1]=a[di[x]]+r[di[x]]; 89 flag=true; 90 } 91 else{ 92 minn[num1]=min(minn[num1],a[di[x]]-r[di[x]]); 93 maxx[num1]=max(maxx[num1],a[di[x]]+r[di[x]]); 94 } 95 } 96 }while(x!=u); 97 } 98 } 99 int lower(long long x){ 100 int ll=1;int rr=tot+1; 101 while(ll<=rr){ 102 int mid=(ll+rr)>>1; 103 if(b[mid]>=x){ 104 tmp=mid; 105 rr=mid-1; 106 } 107 else ll=mid+1; 108 } 109 return tmp; 110 } 111 int uppr(long long x){ 112 int ll=1;int rr=tot+1; 113 while(ll<=rr){ 114 int mid=(ll+rr)>>1; 115 if(b[mid]>x){ 116 tmp=mid; 117 rr=mid-1; 118 } 119 else ll=mid+1; 120 } 121 return tmp; 122 } 123 int main(){ 124 scanf("%d",&n); 125 for(int i=1;i<=n;i++){ 126 scanf("%lld%lld",&a[i],&r[i]); 127 b[i]=a[i]; 128 } 129 tot=unique(b+1,b+1+n)-(b+1); 130 b[tot+1]=4e18; 131 build(1,n,1); 132 for(int i=1;i<=n;i++){ 133 int x=lower(a[i]-r[i]); 134 int y=uppr(a[i]+r[i])-1; 135 update(x,y,1,id[i]); 136 } 137 for(int i=1;i<=num;i++){ 138 if(!dfn[i])Tarjan(i); 139 } 140 for(int i=1;i<=cnt;i++){ 141 if(col[e[i].u]==col[e[i].to])continue; 142 add1(col[e[i].to],col[e[i].u]); 143 in[col[e[i].u]]++; 144 } 145 for(int i=1;i<=num1;i++){ 146 if(in[i]==0)q.push(i); 147 } 148 while(!q.empty()){ 149 int u=q.front(); 150 q.pop(); 151 for(int i=head1[u];i;i=e1[i].nxt){ 152 int v=e1[i].to; 153 in[v]--; 154 if(in[v]==0)q.push(v); 155 minn[v]=min(minn[v],minn[u]); 156 maxx[v]=max(maxx[v],maxx[u]); 157 } 158 } 159 for(int i=1;i<=n;i++){ 160 int x=uppr(maxx[col[id[i]]])-1; 161 int y=lower(minn[col[id[i]]]); 162 ans+=(long long)((long long)(x-y+1)*(long long)i)%mod; 163 ans%=mod; 164 } 165 printf("%lld",ans); 166 return 0; 167 } 168