百度有一位非常有名的大科学家,这位大科学家有很多藏书。
大科学家有一个图书馆,所以放书的容量也随之增加了,图书馆可以看成一个长度为 NNN 的序列,一开始里面放着 NNN 本书,每本书都记载了一个特定元素的信息,书中的元素各不相同。
大科学家会先进行若干次研究,最后进行一次科学实验,这次实验需要选取一些元素放在一起来进行。每次研究,大科学家会从图书馆中的某些位置抽出一些书来看,然后得出“如果 xxx 位置上的书对应的元素被拿来做实验了,那么区间 [l,r][l,r][l,r] 位置上的书对应的元素也必须拿来做实验,否则会爆炸”这样的结论。
大科学家有不止 NNN 本书(也就是说世界上有不止 NNN 种元素),但是他自己没时间给图书馆换书,所以他雇了一个实习生,这个实习生会时不时地拿出一本 从来没被放入图书馆的书,然后替换掉图书馆中某个位置原来的书(所以对于大科学家得到的两次看似一样的研究结果,可能由于图书馆中的书被换了,它们的实质内容可能不一样)。
每本书还记载着对应元素的非负污染值,大科学家希望在完成一次科学实验的前提下(不能不选任何元素),这次实验的总污染值最小。作为一个旁观者,你能看到科学家做的所有研究结果以及实习生换书的顺序,然后你需要告诉大科学家,这个最小总污染值是多少。
由于大科学家精力有限,所以它只能得出不多的实验结论(具体参见数据范围)。
输入格式
第一行一个正整数 NNN,代表图书馆的容量。
接下来一行 NNN 个数,第 iii 个非负整数 aia_iai 代表最开始图书馆中第 iii 本书所描述的元素的污染值。
接下来一行一个整数 MMM,代表事件的总数。
接下来 MMM 行,每行代表一个事件:
若为 000 xxx yyy,代表实习生拿了一本新书替换了 xxx 位置的书,新书对应元素的污染值为 yyy。
若为 111 xxx lll rrr,代表大科学家得到了新的结果,如果 xxx 位置的书对应的元素加入了实验,那么 [l,r][l,r][l,r] 区间内的书对应的元素都必须拿来做实验。
保证大科学家的书籍总数 (N+(N+(N+ 新书数量 )≤105) \le 10^5)≤105。
每个元素的污染值 0≤(ai,y)≤1090 \le (a_i,y) \le 10^90≤(ai,y)≤109。
保证 1≤x≤N1 \le x \le N1≤x≤N,1≤l≤r≤N1 \le l \le r \le N1≤l≤r≤N,M≤105M \le 10^5M≤105。
由于大科学家的精力有限,做不了太多的实验,所以我们保证 ∑(r−l+1)≤105\sum(r-l+1) \le 10^5∑(r−l+1)≤105。
输出格式
输出一个整数,代表最小总污染值。
样例解释
一开始书架上有 555 本书,我们记这些元素的编号顺次为 1,2,3,4,51,2,3,4,51,2,3,4,5,他们的污染值分别为 1,10,100,1000,100001,10,100,1000,100001,10,100,1000,10000。
一共有 444 个事件:
大科学家发现,选了元素 111 就必须选元素 3,43,43,4。
大科学家发现,选了元素 333 就必须选元素 555。
实习生拿了一本新书,我们记这个新元素的编号为 666,他的污染值为 000,替换掉现在书架上的第 333 本书,现在书架上的 555 本书对应元素为 1,2,6,4,51,2,6,4,51,2,6,4,5。
大科学家发现,选了元素 666(因为它在位置 333 上)就必须选元素 1,21,21,2。
于是在所有可能的方案中,单选一个元素 222 来做实验是总污染值最小的,因为如果选择元素 111 或元素 666,都存在一些绑定关系使得总污染值不可能比 101010 更小。
样例输入
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;
}