考前随便做点水题愉♂悦身心 有助于退役

这题意思其实就是说要把外向基环树森林改成一个环的最小代价。

依照套路,先对每棵基环树的树做dp,这里因为要是环,要把所有的树都拆成链,然后连接。所以考虑以最小代价拆掉每一个树。

因为对于树的每层,只能选择出一个儿子作为链的部分保留下来,所以贪心的尽量选权值大的儿子留下来,其他的全部作为另一条链的开头准备接到环上。

所以树的部分就是一个简单的树形DP。

然后看环上的DP,相当于是要把我们之前搞出来的所有的链全部接上去,所以环上至少要有一个边断开,让这些链接上去。

所以环上,每条边要么把入点连着的链断开,接入环中某处,要么直接断掉这条边将一些链给接上去。

这时只要对环上每条边以这两种方案择优选取,最后发现最优方案如果没有环上边被断开,就强制找一个最小的代价让环上边断掉。

当图是一个基环树森林的时候,不影响正确性,我们需要让每棵树的环都断开一个,以互相接入成为环,所以每个基环树可以独立做。

不过注意一个特例:整个图就是一个环,这时就不需要断了。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define mst(x) memset(x,0,sizeof x)
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=1e5+,INF=0x3f3f3f3f;
struct thxorz{
int head[N],nxt[N<<],to[N<<],tot;
thxorz(){tot=;}
inline void add(int x,int y){
to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
}
}G;
ll ans;
int n;
#define y G.to[j]
int vis[N],lp[N],val[N],chain[N],m,lpfa,flag,rt;
void dfs(int x){//dbg(x);
vis[x]=;
for(register int j=G.head[x];j&&!flag;j=G.nxt[j])if(j&){//mistake:the direction of the edge!
if(vis[y])return lpfa=y,flag=,lp[m=]=x,void();
else{dfs(y);if(flag)lp[++m]=x;}
}
if(!flag)vis[x]=;
if(x==lpfa)flag=;
}
void dp(int x){//dbg(x);
vis[x]=;ll sum=;
for(register int j=G.head[x];j;j=G.nxt[j])if(!vis[y])dp(y),sum+=val[y],MAX(chain[x],val[y]);
ans+=sum-chain[x];
}
#undef y
int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
read(n);
for(register int i=,x;i<=n;++i)read(x),read(val[i]),G.add(x,i);
for(register int i=;i<=n;++i)if(!vis[i]){//dbg(i);
flag=,dfs(i);int chosen=;//dbg("ok");dbg(m);
if(m==n)break;
for(register int j=;j<=m;++j)dp(lp[j]);//dbg(lp[j]);
#define nxt (j+1>m?1:j+1)//attention to the order..
for(register int j=;j<=m;++j){
if(chain[lp[j]]<val[lp[nxt]])ans+=chain[lp[j]];
else ans+=val[lp[nxt]],chosen=;
}
if(!chosen){//dbg2(i,chosen);
int tmp=INF;
for(register int j=;j<=m;++j)MIN(tmp,-chain[lp[j]]+val[lp[nxt]]);
ans+=tmp;
}
}
printf("%lld\n",ans);
return ;
}

总结:这题也涉及一个断环的操作,不过是需要考察性质之后发现的,是一个不那么显然的题目。。。

luogu3651 展翅翱翔之时 (はばたきのとき)[基环树+贪心]的更多相关文章

  1. 洛谷P3656 展翅翱翔之时 (はばたきのとき)(洛谷2017.3月赛round1 t4)

    题目背景 船が往くよミライへ旅立とう 船只启航 朝未来展开旅途 青い空笑ってる(なにがしたい?) 湛蓝天空露出微笑(想做些什么?) ヒカリになろうミライを照らしたい 化作光芒吧 想就此照亮未来 輝きは ...

  2. 【洛谷P3651】展翅翱翔之时

    难以吐槽出题人的中二病…… 这题有点类似ZJOI2008 骑士,先跑树上的,最后拆环即可. #include<bits/stdc++.h> #define N 100005 typedef ...

  3. tyvj1940创世纪——贪心(基环树)

    题目:http://www.joyoi.cn/problem/tyvj-1940 基环树的样子,看了书上的讲解,准备写树上DP,然后挂了: #include<iostream> #incl ...

  4. 与图论的邂逅01:树的直径&基环树&单调队列

    树的直径 定义:树中最远的两个节点之间的距离被称为树的直径.  怎么求呢?有两种官方的算法(不要问官方指谁我也不晓得): 1.两次搜索.首先任选一个点,从它开始搜索,找到离它最远的节点x.然后从x开始 ...

  5. COCI2014/2015 Contest#1 D MAFIJA【基环树最大独立点集】

    T1725 天黑请闭眼 Online Judge:COCI2014/2015 Contest#1 D MAFIJA(原题) Label:基环树,断环+树形Dp,贪心+拓扑 题目描述 最近天黑请闭眼在 ...

  6. 【BZOJ1791】【IOI2008】【基环树】island(status第一速度)

      1791: [Ioi2008]Island 岛屿  Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 908  Solved: 159 [Su ...

  7. BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心

    BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...

  8. 『Island 基环树直径』

    Island(IOI 2008) Description 你准备浏览一个公园,该公园由 N 个岛屿组成,当地管理部门从每个岛屿 i 出发向另外一个岛屿建了一座长度为 L_i 的桥,不过桥是可以双向行走 ...

  9. [Codeforces235D]Graph Game——概率与期望+基环树+容斥

    题目链接: Codeforces235D 题目大意:给出一棵基环树,并给出如下点分治过程,求点数总遍历次数的期望. 点分治过程: 1.遍历当前联通块内所有点 2.随机选择联通块内一个点删除掉 3.对新 ...

随机推荐

  1. Django之会话机制cookie、session使用

    login视图函数: def login(request): if request.method == 'POST': username = request.POST.get('username') ...

  2. Linux回收站的路径在哪里?

    linux 回收站的路径:-/.local/share/Trash

  3. Linux 如何找到100M以上的大文件

    find / -type f -size +100000k |xargs ls -lh|awk '{print $9 ":" $5}'

  4. (模板)poj3461(kmp模板题)

    题目链接:https://vjudge.net/problem/POJ-3461 题意:给出主串和模式串,求出模式串在主串中出现的次数. 思路:kmp板子题. AC代码: #include<cs ...

  5. java中讲讲PrintStream的用法,举例?

    [学习笔记] 1.2 PrintStream的用法   从学java第一天,我们就经常用到System.out.println(),实际上查阅文档可知,System.out就是Sun 编的一个Prin ...

  6. 使用JavaScript随机生成数字混合字母的验证码

      <script> // 封装一个随机生成数字的函数 function random(a, b) { var n = Math.round(Math.random() * (a - b) ...

  7. HTNL基础之二

    HTML实体字符 “<”:< “>”:> “空格”: ' / / '  “"”:"  “®”:®  “©”:© 列表 ①无序列表:列表用来在网页上组织信息, ...

  8. 宝塔面板liunx开启ssl域名后无法访问解决方法

    不打开宝塔面板的ssl会不安全,打开了就会提示ssl证书不能使用的错误 如下所示: 您的连接不是私密连接 攻击者可能会试图从 你的ip 窃取您的信息(例如:密码.通讯内容或信用卡信息).了解详情 NE ...

  9. Django-djangorestframework-响应模块

    响应模块 一般都用 Response 对象来做返回(最后一定是打包成符合 HTTP 协议的数据格式来传输,Response 类做了一系列处理,所以这里我们只需要关注下它的那些参数即可) 响应类构造器 ...

  10. LeetCode 899. Orderly Queue

    899. Orderly Queue(有序队列) 题目: 给出了一个由小写字母组成的字符串 S.然后,我们可以进行任意次数的移动. 在每次移动中,我们选择前 K 个字母中的一个(从左侧开始),将其从原 ...