[yLOI2018] 锦鲤抄

先思考图上是\(tag\)的特殊情况。

考虑我们按拓扑序反过来操作,就可以得到我们任意想要的顺序。

那么我们把所有的图都缩点操作,那么我们只需要考虑一个联通分量里就行了。

一个联通分量最后只会剩下一个不可取的,我们只要判断这个就可以了。

那么按照权值大小排序,再一次判断是否可取即可。

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#define ll long long 
#define N 500004

std::stack<int>QWQ;

ll n,m,k;

ll head[N],cnt,scc[N],siz[N],in[N];

struct P{
	int to,next;
}e[N * 10];

inline void add(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}

struct E{
	int w,id;
}p[N];

bool operator < (E a,E b){
	return a.w > b.w;
}

ll dfn[N],low[N],vis[N],dfncnt,sccnt;

inline void tarjan(ll u){
	dfn[u] = low[u] = ++dfncnt;
	QWQ.push(u);
	vis[u] = 1;
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u] = std::min(low[u],low[v]);
		}else if(vis[v]){
			low[u] = std::min(low[u],dfn[v]);
		}
	}
	if(dfn[u] == low[u]){
		++sccnt;
		while(QWQ.top() != u){
			scc[QWQ.top()] = sccnt;
			siz[sccnt] ++ ;
			vis[QWQ.top()] = 0;
			QWQ.pop();
		}
		siz[sccnt] ++ ;
		scc[QWQ.top()] = sccnt;
		vis[QWQ.top()] = 0;
		QWQ.pop();
	}
}

ll ans;

int main(){
	scanf("%lld%lld%lld",&n,&m,&k);
	for(int i = 1;i <= n;++i)
	scanf("%d",&p[i].w),p[i].id = i;
	std::sort(p + 1,p + n + 1);
	for(int i = 1;i <= m;++i){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		add(x,y);
	}
	for(int i = 1;i <= n;++i){
		if(!dfn[i]){
			tarjan(i);
		}
	}
	for(int i = 1;i <= n;++i){
		for(int j = head[i];j;j = e[j].next){
			int v = e[j].to;
			if(scc[v] != scc[i])
			in[scc[v]] ++ ;
		}
	}
	ll got = 0;
	for(int i = 1;i <= n;++i){
		int u = p[i].id;
		if(in[scc[u]])
		got ++ ,ans += p[i].w,siz[scc[u]] -- ;
		else
		if(siz[scc[u]] > 1)
		got ++ ,ans += p[i].w,siz[scc[u]] -- ;
		if(got == k)
		break;
	}
	std::cout<<ans<<std::endl;
}
posted @ 2021-08-11 11:00  fhq_treap  阅读(31)  评论(0编辑  收藏  举报