题目:https://loj.ac/problem/2737

相连的关系形成若干环 / 内向基环树 。如果不是只有一个环的话,就得断开一些边使得图变成若干链。边的边权是以它为出边的点的点权。

基环树的树的部分可以 DP 或者贪心,贪心就是只在分叉处断边。

对于每个环,先做出 f[ i ][ 0/1 ] 表示环上这个点 不向下 / 向下 延伸链的代价,然后在环上 DP 。

方法就是先指定 tot -> 1 的边不选, DP 一番,再制定 tot -> 1 的边选, DP 一番。

如果指定 tot -> 1 的边选,要注意不能连出一个环。所以不仅有 g[ i ][ 0/1 ] 表示 “可以向右延伸” / “无要求” , 还要有一个 [ 0/1 ] 表示 “之前有没有断过” 。不过不用有 g[ i ][ 1 ][ 1 ] ,因为 “无要求” 就是表示 i -> i+1 得断开,这样就一定 “断过” 了;所以就记 g[ i ][ 2 ] 表示 “之前断过,现在可以向右延伸” 。 g[ tot ][ 2 ] 就是指定 tot -> 1 的边选的时候加给答案的贡献。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
ll Mn(ll a,ll b){return a<b?a:b;}
ll Mx(ll a,ll b){return a>b?a:b;}
const int N=1e5+; const ll INF=1e14+;
int n,hd[N],xnt,to[N<<],nxt[N<<],w[N<<],tp[N],tw[N],tot;
int cd[N],cnt,col[N],tim,dfn[N],low[N],sta[N],top;
ll ans,f[N][],g[N][]; bool vis[N],ins[N];
void add(int x,int y,int z)
{
to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;cd[x]++;
}
void tarjan(int cr)
{
dfn[cr]=low[cr]=++tim; sta[++top]=cr; ins[cr]=;
for(int i=hd[cr],v;i;i=nxt[i])
if(!dfn[v=to[i]])tarjan(v),low[cr]=Mn(low[cr],low[v]);
else if(ins[v])low[cr]=Mn(low[cr],dfn[v]);
if(dfn[cr]==low[cr])
{
cnt++; int siz=;
do{
ins[sta[top]]=; col[sta[top]]=cnt; siz++;
}while(sta[top--]!=cr);
if(siz==)col[cr]=, cnt--;
}
}
void dfs(int cr)
{
ins[cr]=;
for(int i=hd[cr],v;i;i=nxt[i])
if(!col[v=to[i]])
{
dfs(v=to[i]);
ll t0=f[cr][]+f[v][]+w[i];
ll t1=Mn(f[cr][]+f[v][],f[cr][]+f[v][]+w[i]);
f[cr][]=t0; f[cr][]=t1;
}
}
void ini_dfs(int cr,int st)
{
dfs(cr); tp[++tot]=cr;
for(int i=hd[cr],v;i;i=nxt[i])
if(col[v=to[i]])
{tw[tot]=w[i]; if(v!=st)ini_dfs(v,st);}
}
void solve(int cr)
{
tot=; ini_dfs(cr,cr);
g[][]=tw[tot]+f[tp[]][]; g[][]=tw[tot]+f[tp[]][];//f[tp[]]!!
for(int i=;i<=tot;i++)
{
int cr=tp[i];//
g[i][]=Mn(g[i-][],g[i-][]+tw[i-])+f[cr][];
g[i][]=Mn(g[i-][],g[i-][]+tw[i-])+f[cr][];
}
ll ret=g[tot][];
g[][]=f[tp[]][]; g[][]=f[tp[]][]; g[][]=g[][]=INF;
for(int i=;i<=tot;i++)
{
int cr=tp[i];
g[i][]=Mn(g[i-][],g[i-][]+tw[i-])+f[cr][];
g[i][]=Mn(g[i-][],g[i-][]+tw[i-])+f[cr][];
g[i][]=Mn(g[i-][],g[i-][]+tw[i-])+f[cr][];
}
ans+=Mn(ret,g[tot][]);
}
int main()
{
n=rdn();
for(int i=,d,z;i<=n;i++)
{ d=rdn(); z=rdn(); add(d,i,z);}
bool fg=;for(int i=;i<=n;i++)if(cd[i]!=){fg=;break;}
if(!fg)
{
int cr=;while(!vis[cr]){vis[cr]=;cr=to[hd[cr]];}
for(int i=;i<=n;i++)if(!vis[i]){fg=;break;}
if(!fg){puts("");return ;}
}
for(int i=;i<=n;i++)if(!dfn[i])tarjan(i);
for(int i=;i<=n;i++)
if(!ins[i]&&col[i])solve(i);
printf("%lld\n",ans); return ;
}

最新文章

  1. O365(世纪互联)SharePoint 之调查列表简单介绍
  2. Python作业 1
  3. 调度系统任务创建---创建一个JoinTrigger的依赖任务(五)
  4. weblogic myeclipse小知识
  5. sql点滴46—Can&#39;t connect to MySQL server (10060)
  6. 一、HTML和CSS基础--HTML+CSS基础课程--第2部分
  7. CentOS 最小化安装后安装桌面
  8. edX开发部署开篇
  9. 现代OpenGL教程 01 - 入门指南
  10. 旧版QT的名称:qt-win-commercial-4.4.3-vc60.exe
  11. ubuntu ssh重启
  12. mysql数据库基于linux的安装步骤及数据库操作
  13. 【原创】python嗅探QQ消息实战
  14. 项目Alpha冲刺(团队)-第六天冲刺
  15. 转《trackingjs+websocket+百度人脸识别API,实现人脸签到》流程
  16. Nginx增加模块
  17. socket编程函数
  18. Ubuntu vi 上下左右变ABCD问题解决方法
  19. [BZOJ4246]两个人的星座(计算几何)
  20. Android中Activity的LauchMode(加载模式)

热门文章

  1. oracle 12c 警告日志位置
  2. 在使用Idea配置jQuery的问题
  3. C# string 与 String的区别
  4. API/SPI可扩展设计原则(转)
  5. angular5 自定义指令 输入输出 @Input @Output(右键点击事件传递)
  6. C++---String类小结
  7. react-native 自定义 下拉刷新 / 上拉加载更多 组件
  8. 增加临时表空间组Oracle11g单实例
  9. js学习:return arguments
  10. 项目报错 exception &#39;RedisException&#39; with message &#39;Redis server went away&#39; in XXX