百度有一位非常有名的大科学家,这位大科学家有很多藏书。
大科学家有一个图书馆,所以放书的容量也随之增加了,图书馆可以看成一个长度为 NN 的序列,一开始里面放着 NN 本书,每本书都记载了一个特定元素的信息,书中的元素各不相同。
大科学家会先进行若干次研究,最后进行一次科学实验,这次实验需要选取一些元素放在一起来进行。每次研究,大科学家会从图书馆中的某些位置抽出一些书来看,然后得出“如果 xx 位置上的书对应的元素被拿来做实验了,那么区间 [l,r][l,r] 位置上的书对应的元素也必须拿来做实验,否则会爆炸”这样的结论。
大科学家有不止 NN 本书(也就是说世界上有不止 NN 种元素),但是他自己没时间给图书馆换书,所以他雇了一个实习生,这个实习生会时不时地拿出一本 从来没被放入图书馆的书,然后替换掉图书馆中某个位置原来的书(所以对于大科学家得到的两次看似一样的研究结果,可能由于图书馆中的书被换了,它们的实质内容可能不一样)。
每本书还记载着对应元素的非负污染值,大科学家希望在完成一次科学实验的前提下(不能不选任何元素),这次实验的总污染值最小。作为一个旁观者,你能看到科学家做的所有研究结果以及实习生换书的顺序,然后你需要告诉大科学家,这个最小总污染值是多少。
由于大科学家精力有限,所以它只能得出不多的实验结论(具体参见数据范围)。
输入格式
第一行一个正整数 NN,代表图书馆的容量。
接下来一行 NN 个数,第 ii 个非负整数 a_iai 代表最开始图书馆中第 ii 本书所描述的元素的污染值。
接下来一行一个整数 MM,代表事件的总数。
接下来 MM 行,每行代表一个事件:
若为 00 xx yy,代表实习生拿了一本新书替换了 xx 位置的书,新书对应元素的污染值为 yy。
若为 11 xx ll rr,代表大科学家得到了新的结果,如果 xx 位置的书对应的元素加入了实验,那么 [l,r][l,r] 区间内的书对应的元素都必须拿来做实验。
保证大科学家的书籍总数 (N+(N+ 新书数量 ) \le 10^5)≤105。
每个元素的污染值 0 \le (a_i,y) \le 10^90≤(ai,y)≤109。
保证 1 \le x \le N1≤x≤N,1 \le l \le r \le N1≤l≤r≤N,M \le 10^5M≤105。
由于大科学家的精力有限,做不了太多的实验,所以我们保证 \sum(r-l+1) \le 10^5∑(r−l+1)≤105。
输出格式
输出一个整数,代表最小总污染值。
样例解释
一开始书架上有 55 本书,我们记这些元素的编号顺次为 1,2,3,4,51,2,3,4,5,他们的污染值分别为 1,10,100,1000,100001,10,100,1000,10000。
一共有 44 个事件:
大科学家发现,选了元素 11 就必须选元素 3,43,4。
大科学家发现,选了元素 33 就必须选元素 55。
实习生拿了一本新书,我们记这个新元素的编号为 66,他的污染值为 00,替换掉现在书架上的第 33 本书,现在书架上的 55 本书对应元素为 1,2,6,4,51,2,6,4,5。
大科学家发现,选了元素 66(因为它在位置 33 上)就必须选元素 1,21,2。
于是在所有可能的方案中,单选一个元素 22 来做实验是总污染值最小的,因为如果选择元素 11 或元素 66,都存在一些绑定关系使得总污染值不可能比 1010 更小。
样例输入
5 1 10 100 1000 10000 4 1 1 3 4 1 3 5 5 0 3 0 1 3 1 2
样例输出
10
思路:
会图论的大佬们的一眼题吧,图论小白。这题我们可以直接用tarjan求个强连通分量,然后直接缩点,由于污染值都是正整数,所以最优解一定是存在与出度为0的点处,我们对这些点维护一个最优解即可(因为缩点后从u到v有一条边,代表如果u中有一个点拿来做实验,那么u中所有的点包括他的出边所到的强连通分量都会拿来做实验,这就使得最优解变大,所以这部分我们可以不维护)
强连通分量: 就是该点集内的任意两点之间都可到达。
这里采用tarjan求强连通分量,复杂度O(|V| + |E|)
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int a[maxn],link[maxn];
vector<int>vt[maxn],af[maxn];
ll cost[maxn];
int n,m,cnt,_lock;
int dfn[maxn],low[maxn],belong[maxn],in[maxn];
stack<int>st;
void init()
{
for(int i = 0;i < maxn;++i)
{
vt[i].clear();
af[i].clear();
link[i] = i;
cost[i] = low[i] = dfn[i] = in[i] = belong[i] = 0;
}
cnt = _lock = 0;
return ;
}
void dfs(int x)
{
dfn[x] = low[x] = ++_lock;
st.push(x);
for(int i = 0;i < vt[x].size();++i)
{
int v = vt[x][i];
if(!dfn[v])
{
dfs(v);
low[x] = min(low[x],low[v]);
}
else if(!belong[v])
{
low[x] = min(low[x],dfn[v]);
}
}
if(low[x] == dfn[x])
{
++cnt;
while(!st.empty())
{
int w = st.top();
st.pop();
belong[w] = cnt;
cost[cnt] += a[w];
if(w == x)
break;
}
}
return ;
}
void solve()
{
for(int i = 1;i <= n;++i)
{
for(int j = 0;j < vt[i].size();++j)
{
int v = vt[i][j];
if(belong[i] != belong[v])
{
af[belong[i]].pb(belong[v]);
in[belong[i]]++;
}
}
}
ll mi = 1e18;
for(int i = 1;i <= cnt;++i)
{
if(in[i] == 0)
{
mi = min(mi,cost[i]);
}
}
cout << mi << endl;
return ;
}
int main()
{
while(cin >> n)
{
init();
for(int i = 1;i <= n;++i)
scanf("%lld",&a[i]);
cin >> m;
for(int i = 1;i <= m;++i)
{
int op,x,y,l,r;
scanf("%d",&op);
if(op == 1)
{
scanf("%d %d %d",&x,&l,&r);
for(int j = l;j <= r;++j)
//if(j != x)
vt[link[x]].pb(link[j]);
}
else
{
scanf("%d %d",&x,&y);
link[x] = ++n;
a[n] = y;
}
}
for(int i = 1;i <= n;++i)
{
if(!dfn[i])
dfs(i);
}
solve();
}
return 0;
}