zoukankan      html  css  js  c++  java
  • [bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑

    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
    ",ans);
    100 }
    101 
    View Code
  • 相关阅读:
    对 String 的几个错误认识 X
    用C# 自定义Window7的JumpList(跳转列表) X
    IPv6无状态自动配置功能配合DHCPv6无状态配置功能 实现IPv6自动分配
    H3C S7500E IPV6白皮书
    静默方式执行chkdsk命令
    IPv6基本知识(转载)
    解决win7官方主题themepack无法安装的问题
    英保通等PXE网刻软件的使用
    通过命令提示符修改windows默认打印机
    OFFICE2010出现两个激活信息的处理办法。
  • 原文地址:https://www.cnblogs.com/wls001/p/9718028.html
Copyright © 2011-2022 走看看