题目
解题思路:
贪心
或者:
我们把这种每个点入度(或者出度)为1的点称为有向环套树。显然,给出的图是一个环套树森林。我们讨论单个环套树的情况。
如果要两两可以互相交互,那么就是形成强连通。
只有一种结构可以达成:环。
所以说,我们需要找找出每个环套树的最长链。
首先找出环,然后环上的树上有多个孩子的点贪心保留权值大的点,这样变成了外向链。
然后枚举环上的每个点,把这个环破开,然后计算最长的链(你可以想象一下“6”这个数字,对就是这个意思)。
森林可能不连通,所以分别处理。最后复杂度是 O(n)
想学一下这种于是就用了这种写法
Accepted code:
#include<bits/stdc++.h>
#define N 100005
typedef long long ll;
using namespace std;
struct Edge{
int u,v,next;
}G[N<<1];
int head[N],tot=0,vis[N],c[N],q[N],top=0,s[N],n,cnt;
ll sum;
inline int read()
{
int f=0,ag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') ag=-1; c=getchar();}
while(isdigit(c)) f=(f<<1)+(f<<3)+c-48,c=getchar();
return f*ag;
}
inline void add(int u,int v)
{
G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
}
void dfs(int u)
{
vis[u]=1;q[++top]=u;s[u]=1;
int mv=0,mst=0,mn=0;ll ret=0;
for(int i=head[u];i;i=G[i].next)
{
int v=G[i].v; ret+=c[v];
if(c[v]>mn)
c[mv]=0,mst=mn,mn=c[v],c[v]-=mst,mv=v;
else
{if(c[v]>mst) mst=c[v],c[mv]=mn-mst; c[v]=0;}
}
ret-=mn;
for(int i=head[u];i;i=G[i].next)
{
int v=G[i].v;
if(s[v])
{
int minv=(1<<30);
if(v==1&&top==n) {puts("0");exit(0);}
for(int i=top;;i--)
{
minv=min(minv,c[q[i]]);
if(q[i]==v) break;
}
ret+=minv;
}
else if(!vis[v]) dfs(v);
}
sum+=ret; top--; s[u]=0;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
int v=read();c[i]=read();
add(v,i);
}
for(int i=1;i<=n;i++)
if(!vis[i]) dfs(i);
return printf("%lld\n",sum)&0;
}