bzoj5017 [Snoi2017]炸弹

好长时间没写博客了...春季学期的日记似乎是没怎么写, 回头写个总结反思放上来...
这个题首先一看就是图论题, 看两眼就是需要数据结构优化的图论题, 而且肯定是用线段树. 看三眼发现需要tarjan求一下强连通分量.
看四眼看出来引爆一个炸弹, 最终能够引爆的所有炸弹一定是一个连续区间内的所有炸弹, 然后就发现只需要求每个炸弹能够引爆的编号最小和最大的炸弹
也就是从强连通分量缩点之后的DAG上算一下每个SCC能够到达的编号最小/最大的炸弹.
思路清晰自然, 是个不错的题.

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1000005;
struct edge{
    int to, next;
}lst[maxn*40];int len=1;
int first[maxn];
void addedge(int a,int b){
    lst[len].to=b;
    lst[len].next=first[a];
    first[a]=len++;
}
int N;
ll X[maxn], R[maxn];
int left[maxn], right[maxn];
struct seg{
    static int ID;
    int l,r,id;
    seg* ch[2];
    seg(int a,int b):l(a),r(b){
        if(a==b)id=a;
        else id=++ID;
        ch[0]=ch[1]=0;
    }
};
int seg::ID=1;
void build(seg* &root, int L, int R){
    root = new seg(L,R);
    if(L==R)return;
    build(root->ch[0],L,(L+R)>>1);
    build(root->ch[1],((L+R)>>1)+1,R);
    addedge(root->id, root->ch[0]->id);
    addedge(root->id, root->ch[1]->id);
}
void add(seg* rt, int from, int L, int R){
    if(L <= rt->l && rt->r <= R){
        if(from!=rt->id)addedge(from, rt->id);
    }else{
        int mid=(rt->l+rt->r)>>1;
        if(L<=mid)add(rt->ch[0],from,L,R);
        if(R>mid)add(rt->ch[1],from,L,R);
    }
}
int dfn[maxn], low[maxn], T;
int stk[maxn],top=0;
bool ins[maxn];
vector<int> scc[maxn];int cntscc=0;
int belong[maxn];
void dfs(int x){
    dfn[x]=low[x]=++T;
    stk[top++]=x;ins[x]=true;
    for(int pt=first[x];pt;pt=lst[pt].next){
        if(!dfn[lst[pt].to]){
            dfs(lst[pt].to);
            if(low[lst[pt].to]<low[x])low[x]=low[lst[pt].to];
        }else if(ins[lst[pt].to] && dfn[lst[pt].to]<low[x])low[x]=dfn[lst[pt].to];
    }
    if(low[x] == dfn[x]){
        ++cntscc;
        do{
            scc[cntscc].push_back(stk[--top]);
            belong[stk[top]]=cntscc;
            ins[stk[top]]=false;
        }while(stk[top]!=x);
    }
}
void tarjan(){
    for(int i=1;i<=N;++i){
        if(!dfn[i])dfs(i);
    }   
}
int lo[maxn], hi[maxn], vis[maxn];
void DFS(int x){
    vis[x]=1;
    for(vector<int>::iterator p=scc[x].begin();p!=scc[x].end();++p){
        if(1<=(*p) &&(*p)<=N){
            if((*p)>hi[x])hi[x]=*p;
            if((*p)<lo[x])lo[x]=*p;
        }
        for(int pt=first[*p];pt;pt=lst[pt].next){
            int y=belong[lst[pt].to];
            if(!vis[y]){
                DFS(y);
            }
            if(hi[y]>hi[x])hi[x]=hi[y];
            if(lo[y]<lo[x])lo[x]=lo[y];
        }
    }
}
void dp(){
    for(int i=1;i<=cntscc;++i){
        lo[i]=N+1;hi[i]=0;
    }
    for(int i=1;i<=cntscc;++i){
        if(!vis[i])DFS(i);
    }
}
int main(){
    scanf("%d",&N);
    for(int i=1;i<=N;++i){
        scanf("%lld%lld",X+i, R+i);
    }
    for(int i=1;i<=N;++i){
        left[i]=lower_bound(X+1,X+N+1, X[i]-R[i])-X;
        right[i]=upper_bound(X+1, X+N+1, X[i]+R[i])-X-1;
    }
    seg::ID=N;
    seg *root;
    build(root, 1, N);//while(1);
    for(int i=1;i<=N;++i){
        add(root,i,left[i],right[i]);
    }
    tarjan();
    dp();
    int ans=0;
    int mod=(int)(1e9+7);
    
    for(int i=1;i<=N;++i){
        ans = (ans + i * 1ll * (hi[belong[i]]-lo[belong[i]]+1))%mod;
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-07-11 14:39  liu_runda  阅读(470)  评论(0编辑  收藏  举报
偶然想到可以用这样的字体藏一点想说的话,可是并没有什么想说的. 现在有了:文化课好难