P3275 [SCOI2011] 糖果

发布时间 2023-07-22 21:34:44作者: zhujio

P3275 [SCOI2011] 糖果 - 洛谷

没有注意到的点:

  1. 求解的解是最小值,所以用差分约束最长路求解,那么出现了正环就无解,所以如果答案合法tarjan缩点后每个强连通分量中的点(得到的糖果数)只能是相等的
  2. 拓扑排序每个入度为0的的 f [ i ] = 1,因为每个人至少要有一颗糖
  3. 最后计算答案时,计算的是强连通分量的sz*cost
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N=1e5+5;

int n,k;
std::vector<pair<int,int>>edge[N];
std::vector<pair<int,int>>G[N];

//bel数组记录某个点在哪个连通块里面
int dfn[N],low[N],ins[N],bel[N],sz[N],idx,cnt;
int inc[N],f[N];
stack<int>stk;
vector<vector<int>>scc;

void dfs(int x){
    dfn[x]=low[x]=++idx;
    ins[x]=true;
    stk.push(x);
    for(auto [y,v]:edge[x]){
        if(!dfn[y]){
            dfs(y);
            low[x]=min(low[x],low[y]);
        }else{
            if(ins[y])low[x]=min(low[x],dfn[y]);
        }
    }
    if(dfn[x]==low[x]){
        vector<int>c;
        cnt++;
        while(1){
            sz[cnt]++;
            int y=stk.top();
            c.push_back(y);
            ins[y]=false;
            bel[y]=cnt;
            stk.pop();
            if(y==x)break;
        }
        scc.push_back(c);
    }
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>k;
    for(int i=1;i<=k;i++){
        int op,x,y;cin>>op>>x>>y;
        if(op==1){
            edge[x].push_back({y,0});
            edge[y].push_back({x,0});
        }else if(op==2){
            edge[x].push_back({y,1});
        }else if(op==3){
            edge[y].push_back({x,0});
        }else if(op==4){
            edge[y].push_back({x,1});
        }else{
            edge[x].push_back({y,0});
        }
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i])dfs(i);
    }
    for(int x=1;x<=n;x++){
        for(auto [y,v]:edge[x]){
            if(bel[x]==bel[y]&&v==1){
                cout<<-1<<endl;
                return 0;
            }
            if(bel[x]!=bel[y]){
                G[bel[x]].push_back({bel[y],v});
                inc[bel[y]]++;
            }
        }
    }
    queue<int>q;
    for(int i=1;i<=cnt;i++){
        if(!inc[i])q.push(i),f[i]=1;
    }
    while(!q.empty()){
        auto x=q.front();
        q.pop();
        for(auto [y,v]:G[x]){
            if(--inc[y]==0)q.push(y);
            f[y]=max(f[y],f[x]+v);
        }
    }
    int ans=0;
    for(int i=1;i<=cnt;i++)ans+=f[i]*sz[i];
    cout<<ans<<endl;
    return 0;
}