[bzoj5017][线段树优化建边]炸弹

5017: [Snoi2017]炸弹

Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 243 Solved: 95
[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

sol:

比较简单,没有solution,这份代码在bz上面一直compiling然后被kill但是loj能过。

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;

inline int read()
{
    char c;
    bool pd=0;
    while((c=getchar())>'9'||c<'0')
    if(c=='-') pd=1;
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9')
    res=(res<<3)+(res<<1)+c-'0';
    return pd?-res:res;
}
const int N=2100000;
const int M=21000000;
vector<int> q[N];
typedef long long ll;
struct cc
{
    ll x,y;
    friend inline bool operator <(const cc &a,const cc &b)
    {
        return a.x<b.x;
    }
}a[N];
int tot,fir[N],go[M],nex[M],from[M];
inline void add(int x,int y)
{
    nex[++tot]=fir[x];fir[x]=tot;go[tot]=y;from[tot]=x;
}
int low[N],dfn[N],tim,sta[N];
bool vis[N];
int id[N],ID;
inline void tarjan(int u)
{
    dfn[u]=low[u]=++tim;
    sta[++sta[0]]=u;
    vis[u]=1;
    int e,v;
    for(e=fir[u];v=go[e],e;e=nex[e])
    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])
    {
        ++ID;
        do
        {
            v=sta[sta[0]--];
            id[v]=ID;
            vis[v]=0;
            q[ID].push_back(v);
        }while(v!=u);
    }
}
inline void modify(int k,int l,int r,int L,int R,int x)
{
    if(L<=l&&r<=R)
    {
        add(x,k);
        return;
    }
    int mid=l+r>>1;
    if(mid>=L) modify(k<<1,l,mid,L,R,x);
    if(mid< R) modify(k<<1|1,mid+1,r,L,R,x);
}
int pos[N];
inline void build(int k,int l,int r)
{
    if(l==r)
    {
        pos[l]=k;
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    add(k,k<<1);
    add(k,k<<1|1);
}
int sizew,nn,n;
int L[N],R[N],tol[N],tor[N];
int deg[N];
const int pyz=1e9+7;
int tots,firs[N],gos[M];
inline void adds(int x,int y)
{
    nex[++tots]=firs[x];firs[x]=tots;gos[tots]=y;
}
int main()
{
//  freopen("5017.in","r",stdin);
    n=read();
    for(int i=1;i<=n;++i)
    scanf("%lld%lld",&a[i].x,&a[i].y);
    for(sizew=1;sizew<n;sizew<<=1);
    nn=sizew<<1;
    build(1,1,sizew);
    for(int i=1;i<=n;++i)
    {
        cc t=(cc){a[i].x-a[i].y};
        tol[pos[i]]=L[pos[i]]=lower_bound(a+1,a+1+n,t)-a;
        t.x=a[i].x+a[i].y;
        tor[pos[i]]=R[pos[i]]=upper_bound(a+1,a+1+n,t)-a-1;
        modify(1,1,sizew,tol[pos[i]],tor[pos[i]],pos[i]);
    }
    for(int i=1;i<=nn;++i)
    if(!dfn[i]) tarjan(i);
    for(int i=1;i<=ID;++i)
    {
        vector<int>::iterator it;
        int e,v,u;
        L[i]=n;
        R[i]=0;
        for(it=q[i].begin();it!=q[i].end();++it)
        {
            u=*it;
            if(u>=pos[1])
            {
                L[i]=min(L[i],tol[u]);
                R[i]=max(R[i],tor[u]);
            }
        }
    }
    for(int i=1;i<=tot;++i)
    {
        adds(go[i],from[i]);
        if(id[go[i]]!=id[from[i]]) deg[id[from[i]]]++;
    }
    sta[0]=0;
    for(int i=1;i<=ID;++i)
    if(!deg[i]) sta[++sta[0]]=i;
    int t=0,ans=0;
    while(t<sta[0])
    {
        int i=sta[++t];
        vector<int>::iterator it;
        int e,v,u;
        for(it=q[i].begin();it!=q[i].end();++it)
        {
            u=*it;
            for(e=firs[u];v=gos[e],e;e=nex[e])
            if(id[u]!=id[v])
            {
                if(!(--deg[id[v]])) sta[++sta[0]]=id[v];
                L[id[v]]=min(L[id[v]],L[i]);
                R[id[v]]=max(R[id[v]],R[i]);
            }
        }
    }
    for(int i=1;i<=n;++i)
    ans=((ll)ans+(ll)i*(R[id[pos[i]]]-L[id[pos[i]]]+1)%pyz)%pyz;
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值