zoukankan      html  css  js  c++  java
  • BZOJ 5017 炸弹 线段树优化建图 Tarjan缩点 拓扑序 / 递推

    $ Rightarrow $ 戳我进BZOJ原题

    [Snoi2017]炸弹

    Time Limit: 30 Sec $ quad $ Memory Limit: 512 MB
     

    Description

    在一条直线上有 $ N $ 个炸弹,每个炸弹的坐标是 $ X_i $ ,爆炸半径是 $ R_i $ ,当一个炸弹爆炸时,如果另一个炸弹所在位置 $ X_j $ 满足:
    $ X_i−R_i≤X_j≤X_i+R_i $ ,那么,该炸弹也会被引爆。
    现在,请你帮忙计算一下,先把第 $ i $ 个炸弹引爆,将引爆多少个炸弹呢?
     

    Input

    第一行,一个数字 $ N $,表示炸弹个数。
    第 $ 2∼N+1 $ 行,每行 $ 2 $ 个数字,表示 $ X_i,R_i $ ,保证 $ X_i $ 严格递增。
    $ N≤500000 $
    $ −1018≤X_i≤1018 $
    $ 0≤R_i≤2×10^18 $
     

    Output

    一个数字,表示$ sum(i*炸弹i能引爆的炸弹个数),1<=i<=N mod10^9+7 $ 。
     

    Sample Input

     4
     1 1
     5 1
     6 5
     15 15
    

    Sample Output

     32
    

     

    思路

    • 当一个炸弹 $ i $ 被引爆时,对于能过够被当前这颗炸弹 $ i $ 引爆的炸弹 $ j $
      我们肯定要建一条 $ i ightarrow j $ 的边,但是由于题目中的边数较多,所以不可能这样建图

    • 当一个炸弹被引爆,那么最终一共被引爆的炸弹一定是连续的,
      所以就又引出区间问题了,那么区间问题我们就可以用线段树来做。

    • 当 $ i $ 炸弹能将 $ [L,R] $ 的炸弹全部引爆时,就建一条 $ pos_i ightarrow now $ 的边
      那么这样就可能会形成环,因为这颗炸弹处于区间中间,那么就 $ Tarjan $ 缩点。

    • 最后 $ Topsort $ ,反向建图,从最远的点一步一步地推回去,从而解决题目。
       

    代码

    /**************************************************************
        Problem: 5017
        User: PotremZ
        Language: C++
        Result: Accepted
        Time:8472 ms
        Memory:469120 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    #define Mod 1000000007
    #define N 1000005
    const long long inf=4e18;
    vector<int>e[N<<2],G[N<<2];
    int pos[N<<2],mps[N<<2],maxo;
    void build(int o,int l,int r){
        maxo=max(maxo,o);
        if(l==r){
            pos[l]=o;
            mps[o]=l;
            return;
        }
        int mid=l+r>>1;
        build(o<<1,l,mid); build(o<<1|1,mid+1,r);
        e[o].push_back(o<<1);
        e[o].push_back(o<<1|1);
    }
    void updata(int o,int l,int r,int L,int R,int v){
        if(L<=l&&r<=R){
            if(o==v) return;
            e[v].push_back(o);
            return;
        }
        int mid=l+r>>1;
        if(L>mid) updata(o<<1|1,mid+1,r,L,R,v);
        else if(R<=mid) updata(o<<1,l,mid,L,R,v);
        else {
            updata(o<<1,l,mid,L,R,v);
            updata(o<<1|1,mid+1,r,L,R,v);
        }
    }
    stack<int>s;
    int dfn[N<<2],low[N<<2],tim,scc,sR[N<<2],sL[N<<2],bel[N<<2],x[N],r[N];
    bool vis[N<<2];
    inline void tarjan(int u){
        dfn[u]=low[u]=++tim; s.push(u); vis[u]=1;
        for(int i=0;i<e[u].size();++i){
            int v=e[u][i];
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            } else if(vis[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u]){
            ++scc;
            sL[scc]=inf; sR[scc]=-inf;
            do{
                u=s.top(); s.pop(); 
                bel[u]=scc; vis[u]=0;
                if(mps[u]){
                    sR[scc]=max(sR[scc],x[mps[u]]+r[mps[u]]);
                    sL[scc]=min(sL[scc],x[mps[u]]-r[mps[u]]);
                }
            }while(low[u]!=dfn[u]);
        }
    }
    int n,in[N<<2],ans;
    queue<int>q;
    signed main(){
        scanf("%lld",&n);
        build(1,1,n);
        for(int i=1;i<=n;++i)
             scanf("%lld %lld",&x[i],&r[i]);
        for(int i=1;i<=n;++i){
            int L=lower_bound(x+1,x+1+n,x[i]-r[i])-x;
            int R=upper_bound(x+1,x+1+n,x[i]+r[i])-x-1;
            updata(1,1,n,L,R,pos[i]);
        }
        for(int i=1;i<=maxo;++i) if(!dfn[i]) tarjan(i);
        for(int i=1;i<=maxo;++i)
            for(int j=0;j<e[i].size();++j){
                int v=e[i][j];
                if(bel[i]!=bel[v]){
                    G[bel[v]].push_back(bel[i]);
                    ++in[bel[i]];
                }
            }
        for(int i=1;i<=scc;++i){
            if(in[i]==0) q.push(i);
        }
        while(!q.empty()){
            int u=q.front(); q.pop();
            for(int i=0;i<G[u].size();++i){
                int v=G[u][i];
                sL[v]=min(sL[v],sL[u]);
                sR[v]=max(sR[v],sR[u]);
                --in[v];
                if(in[v]==0) q.push(v);
            }
        }
        for(int i=1;i<=n;++i){
            int L=lower_bound(x+1,x+n+1,sL[bel[pos[i]]])-x;
            int R=upper_bound(x+1,x+n+1,sR[bel[pos[i]]])-x-1;
            ans=(ans+(R-L+1)*i%Mod)%Mod;
        }
        printf("%lld",ans);
        return 0;
    }
    

     

    PS.

    这道题其实可以 $ O(n) $ 递推过,递推思想和上面差不多,就直接放代码了

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define maxn 500010
    #define int long long
    #define mod 1000000007
    int n,x[maxn],r[maxn],L[maxn],R[maxn],ans;
    signed main(){
    	scanf("%lld",&n);
    	for(int i=1;i<=n;++i) scanf("%lld %lld",&x[i],&r[i]);
    	for(int i=1;i<=n;++i){
    		L[i]=i;
    		while(L[i]>1&&x[i]-x[L[i]-1]<=r[i]){
    			L[i]=L[L[i]-1];
    			r[i]=max(r[i],r[L[i]]-(x[i]-x[L[i]]));
    		}
    	}
    	for(int i=n;i;--i){
    		R[i]=i;
    		while(R[i]<n&&x[R[i]+1]-x[i]<=r[i]){
    			R[i]=R[R[i]+1]; 
    			L[i]=min(L[i],L[R[i]]);
    		}
    	}
    	for(int i=1;i<=n;++i) ans=(ans+i*(R[i]-L[i]+1)%mod)%mod;
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    Direct3D 11 Tutorial 4: 3D Spaces_Direct3D 11 教程4:3D空间
    Direct3D 11 Tutorial 3: Shaders and Effect System_Direct3D 11 教程3:着色器和效果系统
    Direct3D 11 Tutorial 2: Rendering a Triangle_Direct3D 11 教程2:渲染一个三角形
    Direct3D 11 Tutorial 1: Basics_Direct3D 11 教程1:基础
    使用git命令push到自己的仓库,显示Unknown且没有贡献记录的解决方案
    数据结构与算法笔试面试题整理
    网络笔试面试题整理
    C++笔试面试题整理
    使用.gitignore删除Github上的.idea文件
    做游戏服务器端开发时的一些收获与总结
  • 原文地址:https://www.cnblogs.com/PotremZ/p/BZOJ5017.html
Copyright © 2011-2022 走看看