题意:

科学家有一个容量为N的书架,书里有元素,每个元素有一个污染值。

有两种操作,

实习生拿了一本新书替换了x位置的书,新书对应元素的污染值为y。

大科学家得到了新的结果,如果x位置的书对应的元素加入了实验,那么[l,r]区间内的书对应的元素都必须拿来做实验。

大科学家希望在完成一次科学实验的前提下(不能不选任何元素),这次实验的总污染值最小。问这个最小的总污染值是多少。

保证大科学家的书籍总数

每个元素的污染值

保证

保证

思路:

这道题在写简单的时候就已经筋疲力尽了…题意描述不清楚啊…

看题目的时候范围又看错了…以为挨个建边会TLE…没看到求和符号啊相当于直接就想下一题(困难)了?

延续上一题的思路,上一题建完图之后对于每个点跑dfs然后找出总污染值最小的那个点,但是这里就不能这么做了,考虑到总污染值最小的总是出度为0的那个点。

但是如果存在环呢?那不就没有出度为0的点了吗?所以这里就要用到tarjan缩点啦。

缩点之后找出度为0的强连通分量,找出强连通分量里总污染值里最小的那个即可。

其实这题还是很简单的啊…做的时候真的傻了…题目数据范围都没看清楚…还是要仔细读题啊…

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<queue>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
ll val[100010];
int a[100010];//当前书架上放的元素
vector<int>v[100010];
vector<int>scc[100010];
int dfn[100010];//在DFS中该节点被搜索的次序
int low[100010];//i或i的子树能够追溯到的最早的栈中节点的次序号
int sccn[100010];//缩点数组,表示某个点对应的强连通分量编号
int ot[100010];//每个强连通分量的出度
bool vis[100010];//是否在栈中
int step;
int cnt;//强连通分量编号
stack<int>s;
void tarjan(int u)
{
    dfn[u]=low[u]=++step;
    vis[u]=true;
    s.push(u);
    for(int i=0;i<v[u].size();i++)
    {
        int temp=v[u][i];
        if(!dfn[temp])//没有被访问过
        {
            tarjan(temp);
            low[u]=min(low[u],low[temp]);
        }
        else if(vis[temp])//在栈中
            low[u]=min(low[u],dfn[temp]);
    }
    if(low[u]==dfn[u])//构成强连通分量
    {
        cnt++;
        while(1)
        {
            int temp=s.top();
            s.pop();//此点以上的点全部出栈,构成一个强连通分量
            vis[temp]=false;
            sccn[temp]=cnt;//cnt是强连通分量的序号
            scc[cnt].push_back(temp);
            if(temp==u)break;
        }
    }
}
int main()
{
    int n,m,op;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&val[i]);
        a[i]=i;
    }
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&op);
        if(op==0)
        {
            int x;
            ll y;
            scanf("%d%lld",&x,&y);
            val[++n]=y;
            a[x]=n;
        }
        else if(op==1)
        {
            int x,l,r;
            scanf("%d%d%d",&x,&l,&r);
            for(int i=l;i<=r;i++)
                v[a[x]].push_back(a[i]);
        }
    }
    step=cnt=0;
    memset(dfn,0,sizeof(dfn));
    memset(sccn,0,sizeof(sccn));
    fill(vis+1,vis+n,false);
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    memset(ot,0,sizeof(ot));
    for(int i=1;i<=n;i++)
    for(int j=0;j<v[i].size();j++)
    {
        int temp=v[i][j];
        if(sccn[i]!=sccn[temp])//如果i点与他指向的点不在同一个强连通分量中
            ot[sccn[i]]++;//i点所在的强连通分量的出度+1
    }
    ll ans=INF;
    for(int i=1;i<=cnt;i++)
    {
        if(ot[i]==0)
        {
            ll sum=0;
            for(int j=0;j<scc[i].size();j++)
                sum+=val[scc[i][j]];
            ans=min(ans,sum);
        }
    }
    printf("%lld\n",ans);
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

上海高校金马五校赛B DFS+预处理 Previous
HDU4848 搜索+剪枝 Next