zoukankan      html  css  js  c++  java
  • P5025 [SNOI2017]炸弹

     这题非常显然可以用线段树+拓排水过去,但是稍微看了下第一名的时间,非常显然有更优的建法。

    发现轰炸到的区间一定是连续的,于是每个点只要让左右能炸到它的最近的点向它连边就行了,单调栈解决。

    然后缩点加拓排。交上去发现还是慢了不少,发现前几都用基数排序优化了下,不过本人比较懒,还是鸽了。

    代码如下。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cstring>
    #include<cmath>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const ll N=5e5+10,mod=1e9+7;
    struct node{ll l,r,x,d;}a[N];queue<int> q;
    ll n,m,ans,t,num,tot,tc,cnt,top,d[N],du[N],ls[N],rs[N],b[N],c[N],s[N],stack[N],ins[N],dfn[N],low[N],head[N],ver[N*2],next[N*2],hc[N],vc[N*2],nc[N*2];
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    inline bool operator<(const node&x,const node&y){
        return x.x<y.x;
    }
    inline void add(int x,int y){
        ver[++tot]=y;next[tot]=head[x];head[x]=tot;
    }
    inline void add_c(int x,int y){
        vc[++tc]=y;nc[tc]=hc[x];hc[x]=tc;
    }
    inline void tarjan(int x){
        dfn[x]=low[x]=++num;
        stack[++top]=x;ins[x]=1;
        for(int i=head[x];i;i=next[i]){
            if(!dfn[ver[i]]) tarjan(ver[i]),low[x]=min(low[x],low[ver[i]]);
            else if(ins[ver[i]]) low[x]=min(low[x],dfn[ver[i]]);
        }
        if(dfn[x]==low[x]){
            ++cnt;int y;
            do{
                y=stack[top--];c[y]=cnt;ins[y]=0;
                ls[cnt]=min(ls[cnt],1ll*y);
                rs[cnt]=max(rs[cnt],1ll*y);
            }while(x!=y);
        }
    }
    int main(){
        m=n=read();for(int i=1;i<=n;i++) ls[i]=n+1,b[i]=a[i].x=read(),a[i].d=read();
        sort(a+1,a+1+n);sort(b+1,b+1+m);m=unique(b+1,b+1+m)-(b+1);
        for(int i=1;i<=n;i++){
            a[i].l=lower_bound(b+1,b+1+m,a[i].x-a[i].d)-b;
            a[i].r=upper_bound(b+1,b+1+m,a[i].x+a[i].d)-(b+1);
            a[i].x=lower_bound(b+1,b+1+m,a[i].x)-b;
        }
        for(int i=1;i<=n;i++){
            while(top&&a[s[top]].r<a[i].x) top--;
            if(top&&a[s[top]].r>=a[i].x) add(s[top],i);
            while(top&&a[s[top]].r<=a[i].r) top--;
            s[++top]=i;
        }
        top=0;
        for(int i=n;i>=1;i--){
            while(top&&a[s[top]].l>a[i].x) top--;
            if(top&&a[s[top]].l<=a[i].x) add(s[top],i);
            while(top&&a[s[top]].l>=a[i].l) top--;
            s[++top]=i;
        }
        top=0;
        for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        for(int x=1;x<=n;x++){
            for(int i=head[x];i;i=next[i]){
                int y=ver[i];
                if(c[x]==c[y]) continue;
                add_c(c[x],c[y]);du[c[y]]++;
            }
        }
        for(int i=1;i<=cnt;i++) if(!du[i]) q.push(i);
        while(q.size()){
            int x=q.front();q.pop();d[++t]=x;
            for(int i=hc[x];i;i=nc[i]){
                if(!(--du[vc[i]])) q.push(vc[i]);
            }
        }
        for(int j=t;j>=1;j--){
            int x=d[j];
            for(int i=hc[x];i;i=nc[i]){
                int y=vc[i];
                ls[x]=min(ls[x],ls[y]);
                rs[x]=max(rs[x],rs[y]);
            }
        }
        for(int i=1;i<=n;i++) ans=(ans+1ll*i*(rs[c[i]]-ls[c[i]]+1)%mod)%mod;
        return printf("%lld
    ",ans),0;
    }
  • 相关阅读:
    .NET泛型中的协变与逆变
    使用 Roslyn引擎动态编译代码
    Windows 自动更新服务恢复
    She Left Her Shoes
    .NET Core 配置
    EFCore中SQLSERVER 2008 的分页问题
    SQL SERVER 2012/ 2014 分页,用 OFFSET,FETCH NEXT改写ROW_NUMBER的用法(转)
    TFS命令行操作
    负载均衡(Load Balancing)学习笔记(三)
    负载均衡(Load Balancing)学习笔记(二)
  • 原文地址:https://www.cnblogs.com/xtkm/p/10827310.html
Copyright © 2011-2022 走看看