题目链接
裸题,Tarjan 缩点,找到那一个出度为 的点,把它所在的强连通分量的大小输出。如果有多个就无解。
这题是贺我们老师的,所以码风不像我的。
题目链接
这个半连通子图和强连通分量的定义很像,可以发现,强连通分量必定是半连通子图,所以我们先 Tarjan 缩点,变成一个 DAG。然后再想,两个强连通分量通过一条有向边相连,必定是一个半连通子图。所以,问题就变成了再缩完点的 DAG 上寻找最长链。
然后进行拓扑排序,边排序边 DP, 表示到节点 的最长链大小, 表示到节点 最长链个数,要记得判重边。
题目链接
第一问很好解决,缩点后寻找入度为 的点即可。
对于第二问,要求加边,使缩点后的每个点都能到另一个点,即每个点都需要有入度和出度都大于 ,即我们寻找入度为 的点和出度为 的点,取最大值即可。
题目链接
跟上一题一样的,还不要第二问。
题目链接
这一题跟前几题不同,跑 Tarjan 的条件要多一个可以被收买,因为在一个强连通分量中必须要有一个可以被收买的才能够全部逮捕。
缩点的时候记录一下最少的收买值。统计答案时如果有一个点的时间戳没有被更新过,那就代表他既不能被收买,也不能被别人告发,那就是不可控制。
找到所有入度为 的点,加上它的收买值就好了。
题目链接
既然可以重复走,那我们先缩点,每个点的点权定义为这个强连通分量里面 ATM 的和,然后把点权移到边权,跑最长路,最后再枚举每一个酒吧,取最长路的最大值。
#include<bits/stdc++.h>
#define int long long
using namespace std;
void read(int &x)
{
char ch=getchar();
int r=0,mp=1;
while(!isdigit(ch))mp=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
x=r*mp;
}
const int N=1e6+7;
int n,m,k,dfncnt,size,top,scc;
int dfn[N],low[N],stk[N],sc[N],sum[N],du[N],f[N],my[N],sb[N];
int d[N],pre[N],dis[N],son[N],now[N],tot;
bool in_stack[N],bb[N];
map<pair<int,int>,bool>mp;
vector<int>edge[N];
void add(int x,int y,int z)
{
pre[++tot]=now[x];
son[tot]=y;
dis[tot]=z;
now[x]=tot;
}
queue<int>q;
void tarjan(int u)
{
dfn[u]=low[u]=++dfncnt;
stk[++top]=u;
in_stack[u]=1;
for(int v:edge[u])
{
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else
{
if(in_stack[v])
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
scc++;
do
{
sc[stk[top]]=scc;
sum[scc]+=my[stk[top]];
in_stack[stk[top]]=0;
top--;
}
while(stk[top+1]!=u);
}
}
void spfa(int s)
{
queue<int>q;
memset(d,128,sizeof d);
memset(bb,false,sizeof bb);
d[s]=sum[s];q.push(s);bb[s]=1;
while(!q.empty())
{
int u=q.front();q.pop();
bb[u]=0;
for(int i=now[u];i;i=pre[i])
{
int v=son[i],w=dis[i];
if(d[v]<d[u]+w)
{
d[v]=d[u]+w;
if(!bb[v])q.push(v),bb[v]=1;
}
}
}
}
main()
{
read(n);read(m);
for(int i=1,x,y;i<=m;i++)
{
read(x);read(y);
edge[x].push_back(y);
}
for(int i=1;i<=n;i++)
read(my[i]);
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
int s,p;
read(s);read(p);
for(int i=1;i<=p;i++)
read(sb[i]);
for(int u=1;u<=n;u++)
{
for(int v:edge[u])
if(sc[u]!=sc[v]&&mp[make_pair(sc[u],sc[v])]!=1)
{
add(sc[u],sc[v],sum[sc[v]]);
mp[make_pair(sc[u],sc[v])]=1;
}
}
spfa(sc[s]);
int ans=0;
for(int i=1;i<=p;i++)
ans=max(ans,d[sc[sb[i]]]);
cout<<ans;
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效