码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑

时间:2018-09-28 13:45:11      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:space   none   cc++   引爆   head   半径   isp   one   tar   

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缩点+线段树优化建图+拓扑

标签:space   none   cc++   引爆   head   半径   isp   one   tar   

原文地址:https://www.cnblogs.com/wls001/p/9718028.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!