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求强连通分量。最后拓扑合并答案。

  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 
View Code
原文地址:https://www.cnblogs.com/Xu-daxia/p/9407950.html