zoukankan      html  css  js  c++  java
  • BZOJ5017 Snoi2017炸弹(线段树+强连通分量+缩点+传递闭包)

      容易想到每个炸弹向其能引爆的炸弹连边,tarjan缩点后bitset传递闭包。进一步发现每个炸弹能直接引爆的炸弹是一段连续区间,于是线段树优化建图即可让边的数量降至O(nlogn)。再冷静一下由于能间接引爆的炸弹也是一段连续区间,传递闭包时只要记录可达点的左右端点即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 500010
    #define M N<<2
    #define ll long long
    #define P 1000000007
    ll read()
    {
        ll x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,p[M],dfn[M],low[M],stk[M],Set[M],L[M],R[M],root,t,cnt,top,tot,ans=0;
    bool flag[M];
    ll a[N],b[N];
    struct data{int to,nxt;
    }edge[M<<2];
    struct data2{int l,r;
    }tree[M];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void build(int &k,int l,int r)
    {
        if (l==r) {k=l;return;}
        k=++cnt;
        int mid=l+r>>1;
        build(tree[k].l,l,mid);
        build(tree[k].r,mid+1,r);
        addedge(k,tree[k].l),addedge(k,tree[k].r);
    }
    void add(int k,int l,int r,int x,int y,int p)
    {
        if (l==x&&r==y) {addedge(p,k);return;}
        int mid=l+r>>1;
        if (y<=mid) add(tree[k].l,l,mid,x,y,p);
        else if (x>mid) add(tree[k].r,mid+1,r,x,y,p);
        else add(tree[k].l,l,mid,x,mid,p),add(tree[k].r,mid+1,r,mid+1,y,p);
    }
    void tarjan(int k)
    {
        dfn[k]=low[k]=++cnt;stk[++top]=k;flag[k]=1;
        for (int i=p[k];i;i=edge[i].nxt)
        if (!dfn[edge[i].to]) tarjan(edge[i].to),low[k]=min(low[k],low[edge[i].to]);
        else if (flag[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]);
        if (dfn[k]==low[k])
        {
            tot++;L[tot]=n+1,R[tot]=0;
            while (stk[top]!=k)
            {
                Set[stk[top]]=tot;
                if (stk[top]<=n) L[tot]=min(L[tot],stk[top]),R[tot]=max(R[tot],stk[top]);
                flag[stk[top]]=0;
                top--;
            }
            Set[k]=tot;if (k<=n) L[tot]=min(L[tot],k),R[tot]=max(R[tot],k);flag[k]=0,top--;
        }
    }
    namespace newgraph
    {
        int p[M]={0},degree[M]={0},q[M],t=0;
        struct data{int to,nxt;}edge[M<<1];
        void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;degree[y]++;}
        void topsort()
        {
            int head=0,tail=0;
            for (int i=1;i<=tot;i++) if (!degree[i]) q[++tail]=i;
            while (tail<tot)
            {
                int x=q[++head];
                for (int i=p[x];i;i=edge[i].nxt)
                {
                    degree[edge[i].to]--;
                    if (!degree[edge[i].to]) q[++tail]=edge[i].to;
                }
            }
        }
        void dp()
        {
            for (int i=tot;i>=1;i--)
            {
                int x=q[i];
                for (int j=p[x];j;j=edge[j].nxt)
                L[x]=min(L[x],L[edge[j].to]),R[x]=max(R[x],R[edge[j].to]);
            }
        }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5017.in","r",stdin);
        freopen("bzoj5017.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read();
        for (int i=1;i<=n;i++) a[i]=read(),b[i]=read();
        cnt=n;
        build(root,1,n);
        for (int i=1;i<=n;i++)
        {
            int x,y;
            int l=1,r=i;
            while (l<=r)
            {
                int mid=l+r>>1;
                if (a[i]-b[i]<=a[mid]) x=mid,r=mid-1;
                else l=mid+1;
            }
            l=i,r=n;
            while (l<=r)
            {
                int mid=l+r>>1;
                if (a[i]+b[i]>=a[mid]) y=mid,l=mid+1;
                else r=mid-1;
            }
            add(root,1,n,x,y,i);
        }
        t=cnt;cnt=0;
        for (int i=1;i<=t;i++) if (!dfn[i]) tarjan(i);
        for (int k=1;k<=t;k++)
            for (int i=p[k];i;i=edge[i].nxt)
            if (Set[k]!=Set[edge[i].to]) newgraph::addedge(Set[k],Set[edge[i].to]);
        newgraph::topsort();
        newgraph::dp();
        for (int i=1;i<=n;i++) ans=(ans+1ll*i*(R[Set[i]]-L[Set[i]]+1))%P;
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    使你的 Google Summer of Code 建议被接收的5个技巧
    洗牌算法
    自由--永不妥协
    Google Code Jam 2014 总结
    《神经网络与深度学习》(三) 稀疏编码
    《神经网络与深度学习》(二) 常用模型之自编码器
    《神经网络与深度学习》(四) 受限玻尔兹曼机
    《神经网络与深度学习》(五) 卷积神经网络CNN及tensorflow代码实现示例
    《神经网络与深度学习》(一) 感知机、多层神经网络、BP算法、深度学习
    语义哈希(semanticHashing)
  • 原文地址:https://www.cnblogs.com/Gloid/p/10064740.html
Copyright © 2011-2022 走看看