Loading

4253. 【五校联考7day2】QYQ在艾泽拉斯

Description&Data Constraint

在艾泽拉斯的无尽之海里,有着一群不为人知的由各个种族的冒险者统治的岛屿,这些岛屿都很庞大,足以在上面建造许多的城市,城市之间有一些单向道路连接。

有一天,QYQ无意中发现了这些岛屿,并且发现在每个城市的地下都或多或少埋藏着一些装备、金币、宝物……
可是正当QYQ兴奋不已打算全部把它们拿走时,他却惊奇的发现你的魔法在这里被限制住了,唯一可用的技能就是闪现,而且魔法只够他使用 \(K\) 次这个技能了,每次使用这个技能QYQ只能从一个岛屿上闪现到另外一个岛屿上。每一个岛屿只能登上一次,QYQ可以从任何一个城市开始旅程,在任何一个城市结束旅程。

城市的数量共有 \(n\) 个,有 \(m\) 条道路,每一条道路有两个参数\(u,v\),表示从 \(u\)\(v\) 有一条道路,但你只能由 \(u\)\(v\) 走,两个城市属于相同的岛屿当且仅当暂时将所有道路视为双向道路时可以从其中一个城市走到另一个城市(可以途径其它城市)。
每一个城市都有一个宝物的总价值 \(v_i\),你的任务是帮助QYQ得到最大总价值的宝物,并输出这个值。

\(1\le n\le10^6,1\le m\le10^7,1\le v_i\le10^3,0\le K\le 10^6\)

Solution

给出一个有向图,在边无视方向时的连通块被认为是一个岛屿,每个点有点权,然后在每个岛屿上按照方向求出最大价值,问前 \(K\) 大的岛屿的总价值之和。

考虑先 \(\text{tarjan}\)​​ 缩环,求出每个 \(\text{DAG}\)​​。然后对于每个 \(\text{DAG}\)​​,拓扑排序+ \(\text{dp}\) ​​求出最大价值和,最后排序即可。

Code

#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
struct node
{
	int to,next;
}a[N*20];
stack<int> s;
queue<int> q;
int n,m,k,tot,col,cnt,res,w[N],head[N],x[N*10],y[N*10],fa[N],size[N],dfn[N],low[N],ans[N],f[N],rin[N],c[N],v[N];
bool b[N],ins[N];
void add(int x,int y)
{
	a[++tot].to=y;
	a[tot].next=head[x];
	head[x]=tot;
}
void tarjan(int x)
{
	dfn[x]=low[x]=++cnt;
	s.push(x);
	ins[x]=b[x]=true;
	for (int i=head[x];i;i=a[i].next)
	{
		int v=a[i].to;
		if (!b[v])
		{
			tarjan(v);
			low[x]=min(low[x],low[v]);
		}
		else if (ins[v]) low[x]=min(low[x],low[v]);
	}
	if (dfn[x]==low[x])
	{
		++col;
		int h=s.top();s.pop();
		ins[h]=false;c[h]=col;v[col]+=w[h];
		while (x!=h)
		{
			h=s.top();s.pop();
			ins[h]=false;c[h]=col;v[col]+=w[h];
		}
	}
}
int find(int x)
{
	if (fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}
int main()
{
	freopen("azeroth.in","r",stdin);
	freopen("azeroth.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;++i)
	{
		scanf("%d%d",&x[i],&y[i]);
		add(x[i],y[i]);
	}
	for (int i=1;i<=n;++i)
		scanf("%d",&w[i]);
	scanf("%d",&k);
	for (int i=1;i<=n;++i)
		if (!b[i]) tarjan(i);
	tot=0;
	memset(head,0,sizeof(head));
	for (int i=1;i<=col;++i)
		fa[i]=i,size[i]=1;
	for (int i=1;i<=m;++i)
		if (c[x[i]]!=c[y[i]])
		{
			add(c[x[i]],c[y[i]]);
			++rin[c[y[i]]];
			int X=find(c[x[i]]),Y=find(c[y[i]]);
			if (X!=Y)
			{
				if (size[X]<size[Y]) fa[X]=Y,size[Y]+=size[X];
				else fa[Y]=X,size[X]+=size[Y];
			}
		}
	memset(b,false,sizeof(b));
	for (int i=1;i<=col;++i)
		if (!rin[i]) q.push(i);
	while (!q.empty())
	{
		int h=q.front();q.pop();
		f[h]+=v[h];
		ans[find(h)]=max(ans[find(h)],f[h]);
		for (int i=head[h];i;i=a[i].next)
		{
			int t=a[i].to;
			--rin[t];
			f[t]=max(f[t],f[h]);
			if (!rin[t]) q.push(t);
		}
	}
	sort(ans+1,ans+col+1);
	for (int i=col;i>=col-k;--i)
		res+=ans[i];
	printf("%d\n",res);
	return 0;
} 
posted @ 2021-08-09 16:49  Thunder_S  阅读(66)  评论(0编辑  收藏  举报