题目描述
百度有一位非常有名的大科学家,这位大科学家有很多藏书。
大科学家有一个图书馆,所以放书的容量也随之增加了,图书馆可以看成一个长度为$N$的序列,一开始里面放着 $N$ 本书,每本书都记载了一个特定元素的信息,书中的元素各不相同。
大科学家会先进行若干次研究,最后进行一次科学实验,这次实验需要选取一些元素放在一起来进行。每次研究,大科学家会从图书馆中的某些位置抽出一些书来看,然后得出“如果$x$位置上的书对应的元素被拿来做实验了,那么区间$[l,r]$位置上的书对应的元素也必须拿来做实验,否则会爆炸”这样的结论。
大科学家有不止$N$本书(也就是说世界上有不止$N$种元素),但是他自己没时间给图书馆换书,所以他雇了一个实习生,这个实习生会时不时地拿出一本从来没被放入图书馆的书,然后替换掉图书馆中某个位置原来的书(所以对于大科学家得到的两次看似一样的研究结果,可能由于图书馆中的书被换了,它们的实质内容可能不一样)。
每本书还记载着对应元素的非负污染值,大科学家希望在完成一次科学实验的前提下(不能不选任何元素),这次实验的总污染值最小。作为一个旁观者,你能看到科学家做的所有研究结果以及实习生换书的顺序,然后你需要告诉大科学家,这个最小总污染值是多少。
由于大科学家精力有限,所以它只能得出不多的实验结论(具体参见数据范围)。
输入格式
第一行一个正整数 $N$,代表图书馆的容量。
接下来一行 $N$ 个数,第 $i$ 个非负整数 $a_i$ 代表最开始图书馆中第 $i$ 本书所描述的元素的污染值。
接下来一行一个整数 $M$,代表事件的总数。
接下来 $M$ 行,每行代表一个事件:
若为 $0$ $x$ $y$,代表实习生拿了一本新书替换了 $x$ 位置的书,新书对应元素的污染值为 $y$。
若为 $1$ $x$ $l$ $r$,代表大科学家得到了新的结果,如果 $x$ 位置的书对应的元素加入了实验,那么 $[l,r]$ 区间内的书对应的元素都必须拿来做实验。
保证大科学家的书籍总数$(N+ 新书数量)\le 10^5$。
每个元素的污染值 $0\le (a_i,y)\le 10^9$。
保证 $1\le x\le N$,$1 \le l \le r \le N$,$M \le 10^5$。
由于大科学家的精力有限,做不了太多的实验,所以我们保证 $\sum(r-l+1) \le 10^5$。
输出格式
输出一个整数,代表最小总污染值。
样例解释
一开始书架上有 $5$ 本书,我们记这些元素的编号顺次为 $1$,$2$,$3$,$4$,$5$,他们的污染值分别为 $1$,$10$,$100$,$1000$,$10000$。
一共有 $4$ 个事件:
- 大科学家发现,选了元素 $1$ 就必须选元素 $3$,$4$。
- 大科学家发现,选了元素 $3$ 就必须选元素 $5$。
- 实习生拿了一本新书,我们记这个新元素的编号为 $6$,他的污染值为 $0$,替换掉现在书架上的第 $3$ 本书,现在书架上的 $5$ 本书对应元素为 $1$,$2$,$6$,$4$,$5$。
- 大科学家发现,选了元素 $6$(因为它在位置 $3$ 上)就必须选元素 $1$,$2$。
于是在所有可能的方案中,单选一个元素 $2$ 来做实验是总污染值最小的,因为如果选择元素 $1$ 或元素 $6$,都存在一些绑定关系使得总污染值不可能比 $10$ 更小。
样例输入
5
1 10 100 1000 10000
4
1 1 3 4
1 3 5 5
0 3 0
1 3 1 2
样例输出
10
题目链接
思路
看成有向图的话不难发现答案一定在出度为$0$的子图里,只是环比较难以解决,$tarjan$缩点算法可以有效计算强连通分量,即缩圈成点,蓝书上有介绍,强连通分量。
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<stack>
#include<algorithm>
#define MaxN 100000+100
typedef long long LL;
using namespace std;
const LL inf=1e15+7;
LL value[MaxN];
int book[MaxN];
vector<int>G[MaxN];
stack<int>Sta;
stack<int>copy;
int pre[MaxN];
int low_link[MaxN];
int scc[MaxN];
int dfs_cnt,scc_cnt;
LL result=inf;
void dfs(int now)
{
low_link[now]=pre[now]=++dfs_cnt;
Sta.push(now);
for(int i=0;i<G[now].size();i++)
{
int v=G[now][i];
if(!pre[v])
{
dfs(v);
low_link[now]=min(low_link[now],low_link[v]);
}
else
if(!scc[v])
low_link[now]=min(low_link[now],pre[v]);
}
if(low_link[now]==pre[now])
{
LL sum=0;
bool flag=false;
scc_cnt++;
while(1)
{
int u=Sta.top();
scc[u]=scc_cnt;
sum+=value[u];
for(int k=0;k<G[u].size();k++)
if(scc[G[u][k]]!=0 && scc[G[u][k]]<scc_cnt)
flag=true;
Sta.pop();
if(u==now)
break;
}
if(!flag)
result=min(result,sum);
}
}
void find_scc(int N)
{
dfs_cnt=0;
scc_cnt=0;
memset(pre,0,sizeof(pre));
memset(low_link,0,sizeof(low_link));
memset(scc,0,sizeof(scc));
for(int i=1;i<=N;i++)
if(!pre[i])
dfs(i);
}
int main()
{
int N;
scanf("%d",&N);
for(int i=1;i<=N;i++)
scanf("%lld",&value[i]),book[i]=i;
int M;
scanf("%d",&M);
while(M--)
{
int ope;
scanf("%d",&ope);
if(ope==0)
{
int a;
LL b;
scanf("%d %lld",&a,&b);
book[a]=++N;
value[N]=b;
}
else
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
for(int i=b;i<=c;i++)
G[book[a]].push_back(book[i]);
}
}
find_scc(N);
printf("%lld\n",result);
return 0;
}