zoukankan      html  css  js  c++  java
  • 洛谷 P3275 [SCOI2011] 糖果

    题目链接: P3275 [SCOI2011] 糖果

    题目大意:

    (N) 个大于 (0) 的数值,其中有 (M) 对之间的关系已经给出,请求出所有数字和至少有多大,若无解则输出 (-1)
    关系有 (a=b)(a>b)(a<b)(ageq b)(aleq b) 五种。
    (N,Mleq 10^5)

    思路:

    这道题外表看起来是一个差分约束板子(如果你是卡常大师的话那确实如此),不过出题人没有那么良心,他卡了 (SPFA)
    由于每个数字 (geq 1) ,可以设 (d[0]=0) ,让 (forall x,d[x]-d[0]geq 1) ,建完图后,考虑这题有什么特殊性质。
    连边的时候可以发现所有的边权都是 (geq 0) 的,这意味着如果图中出现一个环,则环上的边权必须全为 (0) ,否则必然无解。在这个思路引导下,用 (Tarjan) 求出图中的所有强连通分量,而 (SCC) 在这里的性质与环相同,若有非零边则无解,否则分量中的所有数都应该相等,这时我们可以将其视为一整块,进行缩点,然后便得到了一张 (DAG) ,这样事情就简单了,从节点 (0) 所在的 (SCC) 出发进行拓扑即可得到每个块的最小数值。
    时间复杂度 (O(N+M))

    实现细节:

    • (ans)(long) (long)

    Code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<stack>
    #include<queue>
    #define N 100100
    #define M 300100
    using namespace std;
    inline int read(){
        int s=0,w=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
        return s*w;
    }
    int head[N],to[M],nxt[M],len[M];
    int H[N],T[M],NX[M],L[M];
    int dfn[N],low[N];
    int c[N],siz[N],deg[N],dis[N];
    int cnt,num,scc;
    bool in[N];
    stack<int> s;
    queue<int> q;
    void init(){
        memset(head,-1,sizeof(head));
        memset(H,-1,sizeof(H));
        cnt=-1;
    }
    void add_e(int a,int b,int l){
        nxt[++cnt]=head[a],head[a]=cnt,to[cnt]=b,len[cnt]=l;
    }
    void add_c(int a,int b,int l){
        NX[++cnt]=H[a],H[a]=cnt,T[cnt]=b,L[cnt]=l;
    }
    void tarjan(int x){
        dfn[x]=low[x]=++num;
        s.push(x),in[x]=true;
        for(int i=head[x];~i;i=nxt[i]){
            int y=to[i];
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
            }else if(in[y])
                low[x]=min(low[x],dfn[y]);
        }
        if(dfn[x]==low[x]){
            scc++; int y;
            do{
                y=s.top(),s.pop();
                in[y]=false,c[y]=scc;
                siz[scc]++;
            }while(x!=y);
        }
    }
    void topo(){
        q.push(c[0]);
        while(!q.empty()){
            int cur=q.front(); q.pop();
            for(int i=H[cur];~i;i=NX[i]){
                dis[T[i]]=max(dis[T[i]],dis[cur]+L[i]);
                if(--deg[T[i]]==0)q.push(T[i]);
            }
        }
    }
    int main(){
        int n,k,x,a,b;
        cin>>n>>k;
        init();
        for(int i=0;i<k;i++){
            x=read(),a=read(),b=read();
            switch(x){
                case 1:add_e(a,b,0),add_e(b,a,0); break;
                case 2:add_e(a,b,1); break;
                case 3:add_e(b,a,0); break;
                case 4:add_e(b,a,1); break;
                case 5:add_e(a,b,0);
            }
        }
        for(int i=1;i<=n;i++)add_e(0,i,1);
        tarjan(0);
        cnt=-1;
        for(int i=0;i<=n;i++){
            for(int j=head[i];~j;j=nxt[j]){
                if(c[i]!=c[to[j]])
                    add_c(c[i],c[to[j]],len[j]),deg[c[to[j]]]++;
                else if(len[j])return puts("-1"),0;
            }
        }
        topo();
        long long ans=0;
        for(int i=1;i<=scc;i++)ans+=(long long)siz[i]*dis[i];
        cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    删DS.Store
    switch 多重选择
    PrintWrite写入文件
    读取文件
    notepad++如何把文件保存为java文件
    让notepad++成为轻量级JAVA的IDE
    Jenkins构建Python项目提示:'python' 不是内部或外部命令,也不是可运行的程序
    相关服务账号
    Jenkins安装与启动
    jmeter安装
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/14344303.html
Copyright © 2011-2022 走看看