[Snoi2017] bzoj 5017 - 炸弹 - tarjan - 倍增

8人阅读 评论(0) 收藏 举报
分类:

注意到一个炸弹爆炸后,最终爆炸范围一定是一个区间,只需要维护这个区间按即可。用倍增表维护出,一个炸弹爆炸之后,能引爆的所有炸弹中,左、右端点最远的两枚炸弹,从当前向这两个连边;而其余炸弹可以不用管。然后对于这个图跑tarjan缩点,也就是同一个强连通分量里面的炸弹可以相互引爆,共享左右端点;然后每个点的区间就是其所有后继状态的并,最后询问这个区间内有多少炸弹即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#include<utility>
#include<climits>
#define mp make_pair
#define lint long long
#define N 510000
#define LOG 20
#define M N<<1
#define INF INT_MAX
#define mod 1000000007
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
lint v[N],x[N],r[N];pii fL[N][LOG],fR[N][LOG];int minL[N],scc;
int a[M],b[M],low[N],dfn[N],d[N],Log[N],t[N],maxR[N],cnt[N];
stack<int> s;int state[N],dfc,bel[N],L[N],R[N];bool vis[N];
struct edges{
    int to,pre;
}e[M];int h[N],etop;queue<int> q;
inline int add_edge(int u,int v)
{
    return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop;
}
inline int tarjan(int x)
{
    s.push(x),state[x]=1,low[x]=dfn[x]=++dfc;
    for(int i=h[x],y;i;i=e[i].pre)
        if(!state[y=e[i].to]) tarjan(y),low[x]=min(low[x],low[y]);
        else if(state[y]==1) low[x]=min(low[x],dfn[y]);
    if(low[x]==dfn[x])
    {
        bel[x]=++scc,minL[scc]=L[x],maxR[scc]=R[x];int y;
        while(s.top()^x)
            bel[y=s.top()]=scc,minL[scc]=min(minL[scc],L[y]),
            maxR[scc]=max(maxR[scc],R[y]),s.pop(),state[y]=2;
        s.pop(),state[x]=2;
    }
    return 0;
}
inline int toposort(int n)
{
    int p=0;
    for(int i=1;i<=n;i++)
        if(!d[i]) q.push(i),vis[i]=true,t[++p]=i;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=h[x],y;i;i=e[i].pre)
            if(!(--d[y=e[i].to])) q.push(y),vis[y]=true,t[++p]=y;
    }
    return 0;
}
inline int getdp(int n)
{
    for(int p=n;p>=1;p--)
        for(int x=t[p],i=h[x],y;i;i=e[i].pre)
            y=e[i].to,minL[x]=min(minL[x],minL[y]),maxR[x]=max(maxR[x],maxR[y]);
    return 0;
}
inline int queryL(int L,int R)
{
    int k=Log[R-L+1];
    return min(fL[L][k],fL[R-(1<<k)+1][k]).second;
}
inline int queryR(int L,int R)
{
    int k=Log[R-L+1];
    return max(fR[L][k],fR[R-(1<<k)+1][k]).second;
}
#define gc getchar()
inline lint inn()
{
    lint x;int ch,f=0;while(((ch=gc)<'0'||ch>'9')&&ch!='-');
    if(ch^'-') x=ch^'0';else f=1,x=0ll;
    while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');
    return f?-x:x;
}
int main()
{
    int n,c=0,ec=0;scanf("%d",&n);
    v[++c]=LLONG_MIN,v[++c]=LLONG_MAX;
    for(int i=1;i<=n;i++)
        x[i]=inn(),r[i]=inn(),v[++c]=x[i];
    sort(v+1,v+c+1),c=unique(v+1,v+c+1)-v-1;
    for(int i=1;i<=n;i++)
        L[i]=lower_bound(v+1,v+c+1,x[i]-r[i])-v,
        R[i]=lower_bound(v+1,v+c+1,x[i]+r[i])-v,
        (v[R[i]]>(x[i]+r[i]))?(R[i]--):0,
        x[i]=lower_bound(v+1,v+c+1,x[i])-v;
    for(int i=1;i<=c;i++)
        cnt[i]=0,fL[i][0]=mp(INF,0),fR[i][0]=mp(0,0);
    for(int i=1;i<=n;i++) cnt[x[i]]++,
        fL[x[i]][0]=min(fL[x[i]][0],mp(L[i],i)),
        fR[x[i]][0]=max(fR[x[i]][0],mp(R[i],i));
    for(int i=2;i<=c;i++)
        Log[i]=Log[i>>1]+1,cnt[i]+=cnt[i-1];
    for(int j=1;j<=Log[c];j++)
        for(int i=1;i+(1<<j)-1<=c;i++)
            fL[i][j]=min(fL[i][j-1],fL[i+(1<<(j-1))][j-1]),
            fR[i][j]=max(fR[i][j-1],fR[i+(1<<(j-1))][j-1]);
    for(int i=1,u,v;i<=n;i++)
        u=queryL(L[i],R[i]),v=queryR(L[i],R[i]),
        (u?add_edge(i,u):0),(v?add_edge(i,v):0);
    for(int i=1;i<=n;i++) if(!state[i]) tarjan(i);
    for(int x=1;x<=n;x++)
        for(int i=h[x];i;i=e[i].pre)
            if(bel[x]^bel[e[i].to])
                ec++,a[ec]=bel[x],b[ec]=bel[e[i].to];
    memset(h,0,sizeof(h)),etop=0;
    for(int i=1;i<=ec;i++)
        add_edge(a[i],b[i]),d[b[i]]++;
    toposort(scc),getdp(scc);int ans=0;
    for(int i=1;i<=n;i++)
        (ans+=(lint)i*(cnt[maxR[bel[i]]]-cnt[minL[bel[i]]-1])%mod)%=mod;
    return !printf("%d\n",ans);
}

查看评论

JDBC基础视频课程

了解JDBC的概念和 必要性 了解JDBC驱动程序类型 了解java.sql包 使用JDBC进行 数据库编程 PreparedStatement接口 了解事务
  • 2016年10月13日 14:20

bzoj5017: [Snoi2017]炸弹

线段树优化建图+暴力
  • qq_36797743
  • qq_36797743
  • 2017-09-07 13:30:03
  • 486

5017: [Snoi2017]炸弹

题目链接题目大意:在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆...
  • Mmh2000
  • Mmh2000
  • 2018-02-10 20:36:24
  • 57

bzoj5017 [Snoi2017]炸弹(tarjan缩点+拓扑序dp+线段合并+线段树优化建图)

首先我们可以发现每个点能引爆的炸弹是一个连续的区间。相邻的点能引爆的区间肯定不会相离。每个点向他能引爆的点连边,建出一张有向图,Tarjan缩点(一个scc内的点都可以互达,合并他们能到达的区间即可)...
  • Icefox_zhx
  • Icefox_zhx
  • 2017-12-22 22:07:41
  • 156

[暴力DP][暴力STL]SNOI2017 && LOJ#2256. 英雄联盟

列出DP方程 fi,j=min{fi−1,jk+k×Ci,k|j且k≤Ki }f_{i,j}=min\{ f_{i-1,{j\over k}}+k\times C_i,k|j且k\leq K_i~\...
  • Coldef
  • Coldef
  • 2017-07-06 20:42:47
  • 577

bzoj 5017 炸弹 线段树优化建图+tarjan+拓扑排序

题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引...
  • shiyongyang
  • shiyongyang
  • 2017-09-14 20:21:08
  • 291

[bzoj5017/Snoi2017]炸弹

题目大意在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。 对...
  • WorldWide_D
  • WorldWide_D
  • 2017-10-23 20:36:45
  • 233

bzoj5017 [Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

这题原文地址 题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹...
  • elijahqi
  • elijahqi
  • 2017-12-22 19:13:49
  • 48

最近公共祖先(LCA)算法实现过程 【Tarjan离线+倍增在线+RMQ】

最近公共祖先(LCA) 首先来介绍下最近公共祖先(LCA)的概念 百度上的解释:对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度...
  • my_sunshine26
  • my_sunshine26
  • 2017-05-24 22:31:47
  • 1420

[BZOJ]5018: [Snoi2017]英雄联盟 DP

DP
  • baidu_36797646
  • baidu_36797646
  • 2017-09-02 18:34:08
  • 411
    个人资料
    持之以恒
    等级:
    访问量: 3万+
    积分: 2131
    排名: 2万+
    最新评论