[SNOI2017]炸弹(线段树优化建图)

[SNOI2017]炸弹(luogu)

Solution

  • 此题可以将一个炸弹向它可以引爆的炸弹连一条有向边
  • 然后在建成的图中搜索一个炸弹沿有向边能到的炸弹数为多少
  • 似乎可以用强联通分量缩点来优化?

由于每个炸弹能引爆的炸弹必定是连续的一段,所以缩点时可以记录每个缩后的点代表哪一段炸弹

缩完点后dfs一遍找出缩后的点能引爆哪一段

但出题人太恶意,需要连n2条边。。。

由于连的边总是一段区间,我们考虑能不能用线段树优化

建一棵有n个叶子节点的线段树(父亲向儿子连边,数量级为n),把每个炸弹作为编号对应的叶子节点

然后连边时向对应线段连边,总的连边数在nlogn数量级内

Code

 

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <algorithm>
#define ll long long
#define mid ((l+r)>>1)
#define lc (g<<1)
#define rc ((g<<1)|1)
using namespace std;
const int N=5e5+10,M=2e6+10,P=1e9+7;
vector <int> link[M],son[M],re[M];
int n,id[N],scc,d[M],le[M],ri[M],m;
int top,dfn[M],low[M],tot,st[M],in[M],ans;
ll x[N],r[N];
struct node
{
    int l,r;
    inline node(int l=0,int r=0):l(l),r(r){};
}f[M];
void build(int g,int l,int r)
{
    f[g]=node(l,r);
    m=max(m,g);
    if(l==r)
    {
        id[l]=g;
        return;
    }
    link[g].push_back(lc);
    link[g].push_back(rc);
    build(lc,l,mid);
    build(rc,mid+1,r);
}
void add(int g,int l,int r,int ul,int ur,int v)
{
    if(ul<=l && r<=ur)
    {
        link[v].push_back(g);
        return;
    }
    if(ur<=mid) add(lc,l,mid,ul,ur,v);
    else if(ul>mid) add(rc,mid+1,r,ul,ur,v);
    else add(lc,l,mid,ul,mid,v),add(rc,mid+1,r,mid+1,ur,v);
}
void tarjan(int u)
{
    dfn[u]=low[u]=++tot;
    st[++top]=u,in[u]=1;
    int size=link[u].size();
    for(int i=0;i<size;i++)
    {
        int v=link[u][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(in[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        scc++;
        int z=0;
        do
        {
            z=st[top--];
            d[z]=scc,in[z]=0;
            le[scc]=min(le[scc],f[z].l);
            ri[scc]=max(ri[scc],f[z].r);
        }while(z!=u);
    }
}
void dfs(int u)
{
    in[u]=1;
    int size=re[u].size();
    for(int i=0;i<size;i++)
    {
        int v=re[u][i];
        if(!in[v]) dfs(v);
        le[u]=min(le[u],le[v]);
        ri[u]=max(ri[u],ri[v]);
    }
}
int query(int x)
{ 
    int u=d[id[x]];
    return ri[u]-le[u]+1;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld%lld",&x[i],&r[i]);
    build(1,1,n);
    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;
        add(1,1,n,L,R,id[i]);
    }
    memset(le,0x3f,sizeof(le));
    tarjan(1);
    for(int u=1;u<=m;u++)
    {
        int size=link[u].size();
        for(int i=0,v;i<size;i++)
            if(d[v=link[u][i]]!=d[u])
                re[d[u]].push_back(d[v]);
    }
    dfs(d[1]);
    for(int i=1;i<=n;i++) ans=(ans+(ll)query(i)*i%P)%P;
    printf("%d",ans);
    return 0;
}

 

 

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12723857.html
今日推荐