【JZOJ4253】QYQ在艾泽拉斯

description

在艾泽拉斯的无尽之海里,有着一群不为人知的由各个种族的冒险者统治的岛屿,这些岛屿都很庞大,足以在上面建造许多的城市,城市之间有一些单向道路连接。
有一天,QYQ无意中发现了这些岛屿,并且发现在每个城市的地下都或多或少埋藏着一些装备、金币、宝物……
可是正当QYQ兴奋不已打算全部把它们拿走时,他却惊奇的发现你的魔法在这里被限制住了,唯一可用的技能就是闪现,而且魔法只够他使用K次这个技能了,每次使用这个技能QYQ只能从一个岛屿上闪现到另外一个岛屿上。每一个岛屿只能登上一次,QYQ可以从任何一个城市开始旅程,在任何一个城市结束旅程。
城市的数量共有n个,有m条道路,每一条道路有两个参数u,v,表示从u到v有一条道路,但你只能由u到v走,两个城市属于相同的岛屿当且仅当暂时将所有道路视为双向道路时可以从其中一个城市走到另一个城市(可以途径其它城市)。
每一个城市都有一个宝物的总价值v[i],你的任务是帮助QYQ得到最大总价值的宝物,并输出这个值。


analysis

  • tarjan+DPtarjan+DPtarjan+DP

  • 把原图缩环以后,就变成了若干个DAGDAGDAG

  • 对于所有DAGDAGDAG里的每个点,我们需要连接双向边遍历记录每个点属于哪个DAGDAGDAG

  • 搞完然后就直接从所有入度为000的点开始在这些DAGDAGDAGDPDPDP就好了

  • 统计每个DAGDAGDAG的最大值,那么输出前k+1k+1k+1大的即可


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100005
#define MAXM 1000005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=last[a];i;i=next[i])
#define O3 __attribute__((optimize("-O3")))

using namespace std;

ll last[MAXM],next[MAXM],tov[MAXM];
ll dfn[MAXN],low[MAXN],stack[MAXN],color[MAXN];
ll b[MAXN],d[MAXN],v[MAXN],f[MAXN],g[MAXN],kind[MAXN],h[MAXN];
bool bz[MAXN];
ll n,m,k,tot,top,sum,ans,temp;

struct node
{
	ll x,y;
}a[MAXM];

O3 inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
O3 inline bool cmp(ll x,ll y)
{
	return x>y;
}
O3 inline ll max(ll x,ll y)
{
	return x>y?x:y;
}
O3 inline ll min(ll x,ll y)
{
	return x<y?x:y;
}
O3 inline void link(ll x,ll y)
{
	if (x==y)return;
	d[y]++;
	next[++tot]=last[x],last[x]=tot,tov[tot]=y;
}
O3 inline void tarjan(ll x)
{
	dfn[x]=low[x]=++tot;
	bz[x]=1,stack[++top]=x;
	rep(i,x)
	{
		if (!dfn[tov[i]])
		{
			tarjan(tov[i]);
			low[x]=min(low[x],low[tov[i]]);
		}
		else
		{
			if (bz[tov[i]])low[x]=min(low[x],low[tov[i]]);
		}
	}
	if (dfn[x]==low[x])
	{
		color[x]=++sum,bz[x]=0;
		while (stack[top]!=x)
		{
			color[stack[top]]=sum;
			bz[stack[top--]]=0;
		}
		--top;
	}
}
O3 inline void check(ll x,ll y)
{
	bz[x]=0,kind[x]=y;
	rep(i,x)if (bz[tov[i]])check(tov[i],y);
}
O3 inline void dfs(ll x)
{
	bz[x]=0;
	ll temp=0;
	rep(i,x)if (tov[i]!=x)
	{
		if (bz[tov[i]])dfs(tov[i]);
		f[x]=max(f[x],f[tov[i]]);
	}
	f[x]+=g[x];
}
O3 int main()
{
	freopen("azeroth.in","r",stdin);
	freopen("azeroth.out","w",stdout);
	n=read(),m=read();
	fo(i,1,m)
	{
		ll x=read(),y=read();
		link(x,y),a[i].x=x,a[i].y=y;
	}
	fo(i,1,n)v[i]=read();
	k=read();
	tot=0;
	fo(i,1,n)if (!dfn[i])tarjan(i);
	tot=0;
	memset(last,0,sizeof(last));
	memset(next,0,sizeof(next));
	memset(tov,0,sizeof(tov));
	memset(bz,1,sizeof(bz));
	fo(i,1,m)link(color[a[i].x],color[a[i].y]),link(color[a[i].y],color[a[i].x]);
	fo(i,1,n)if (bz[color[i]])check(color[i],++temp);
	tot=0;
	memset(last,0,sizeof(last));
	memset(next,0,sizeof(next));
	memset(tov,0,sizeof(tov));
	memset(d,0,sizeof(d));
	fo(i,1,m)link(color[a[i].x],color[a[i].y]);
	fo(i,1,n)g[color[i]]+=v[i];
	memset(bz,1,sizeof(bz));
	fo(i,1,n)if (!d[color[i]])
	{	
		dfs(color[i]),d[color[i]]=1;
		h[kind[color[i]]]=max(h[kind[color[i]]],f[color[i]]);
	}
	sort(h+1,h+n+1,cmp);
	fo(i,1,k+1)ans+=h[i];
	printf("%lld\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值