[SNOI2017] 炸弹

link

线段树优化建图,再跑$tarjan$已成$DAG$,然后反跑拓扑排序即可,因为最小的反倒是连边连的最多的地方,即使方向两边入读为$0$的点,然后在随便跑个计数$dp$即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define mod 1000000007
using namespace std;
queue<long long> que;
inline long long read()
{
    long long f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
long long n,r[500001],p[500001],ll[500001],rr[500001],m;
long long query_l(long long pos,long long rrr){
    long long l=1,r=n,minn=2<<30-1,mid,ls=pos-rrr;
    while(l<=r){
        mid=l+r>>1;
        if(p[mid]>=ls) minn=min(minn,mid),r=mid-1;
        else l=mid+1;
    }return minn;
}
long long query_r(long long pos,long long rrr){
    long long l=1,r=n,maxn=0,mid,lr=pos+rrr;
    while(l<=r){
        mid=l+r>>1;
        if(p[mid]<=lr) maxn=max(maxn,mid),l=mid+1;
        else r=mid-1;
    }return maxn;
}
struct node{
    long long u,v,nex;
}x[10999999];
long long head[9500001],vis[9500001],cnt,f[9500001],uu[10999999],vv[10999999];
struct node1{
    long long u,v;
}s[10999999];
void add(long long u,long long v){
    x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
    s[cnt].u=u,s[cnt].v=v;
}
void build(long long k,long long l,long long r){
    if(l==r) {add(k+n,l);return;}
    long long mid=l+r>>1;
    build(k<<1,l,mid),build(k<<1|1,mid+1,r);
    add(k+n,(k<<1)+n),add(k+n,(k<<1|1)+n);
    return;
}
void query(long long k,long long l,long long r,long long x,long long y,long long st){
    if(x<=l&&r<=y){add(st,k+n);return;}
    long long mid=l+r>>1;
    if(x<=mid) query(k<<1,l,mid,x,y,st);
    if(mid<y) query(k<<1|1,mid+1,r,x,y,st);
    return;
}
long long du[10999999],co[10999999],col,ans[10999999],low[10999999],dfn[10999999],sta[10999999],tot,num;
void tarjan(long long xx){
    low[xx]=dfn[xx]=++num;
    sta[++tot]=xx;
    for(long long i=head[xx];i!=-1;i=x[i].nex){
        long long v=x[i].v;
        if(!dfn[v]) {tarjan(v);low[xx]=min(low[xx],low[v]);}
        else if(!co[v]) low[xx]=min(low[xx],dfn[v]);
    }
    if(dfn[xx]==low[xx]){
        co[xx]=++col;
        if(xx>=1&&xx<=n) ans[col]++;
        while(sta[tot]!=xx){
            co[sta[tot]]=col;
            if(sta[tot]>=1&&sta[tot]<=n) ans[col]++;
            tot--;
        }tot--;
    }return;
}
long long dp[19999999];
bool cmp(node1 x1,node1 x2){
    if(x1.u==x2.u) return x1.v<x2.v;
    return x1.u<x2.u;
}
void reset(){
    for(long long i=1;i<=cnt;i++) s[i].u=co[s[i].u],s[i].v=co[s[i].v];
    sort(s+1,s+cnt+1,cmp);
    m=cnt;
    memset(head,-1,sizeof(head)),cnt=0;
    for(long long i=1;i<=m;i++){
        if(((s[i].u!=s[i].v)&&((s[i].u!=s[i-1].u)||(s[i].v!=s[i-1].v)))) {
            add(s[i].v,s[i].u),du[s[i].u]++;
        }
    }
    for(long long i=1;i<=col;i++) dp[i]=ans[i];
    for(long long i=1;i<=col;i++){
        if(!du[i]) que.push(i);
    }
}
void topu(){
    while(!que.empty()){
        long long u=que.front();que.pop();
        for(long long i=head[u];i!=-1;i=x[i].nex){
            dp[x[i].v]+=dp[u];
            du[x[i].v]--;
            if(!du[x[i].v]) que.push(x[i].v);
        }
    }
}
long long sum;
int main()
{
    memset(head,-1,sizeof(head));
    n=read();
    for(long long i=1;i<=n;i++) p[i]=read(),r[i]=read();
    for(long long i=1;i<=n;i++){
        ll[i]=query_l(p[i],r[i]),rr[i]=query_r(p[i],r[i]);
    }
    build(1,1,n);
    for(long long i=1;i<=n;i++) query(1,1,n,ll[i],rr[i],i);
    for(long long i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    reset();
    topu();
    for(long long i=1;i<=n;i++) 
        sum+=i*dp[co[i]],sum%=mod;
    cout<<sum;
}
View Code
原文地址:https://www.cnblogs.com/si-rui-yang/p/9850288.html