【bzoj3832】Rally
Description
给你一个DAG,每条边长度都是\(1\),请找一个点满足删掉这个点之后剩余图中的最长路最短
Solution
这题的话感觉思路挺妙的
因为要涉及到删点操作,所以我们肯定不能通过直接的方法来算最长路,然后因为这题没有固定的起点和终点并且是一个DAG,所以有一个比较简单粗暴的处理方法就是像网络流一样建一个超级源\(S\)和一个超级汇\(T\),每个点都从\(S\)连一条长度为\(0\)的边,每个点都向\(T\)连一条长度为\(0\)的边
我们记\(f[i]\)表示从\(S\)到\(i\)点的最长路,记\(g[i]\)表示从\(i\)点到\(T\)点的最长路,这两个东西都可以按拓扑序转移直接dp出来(正反各来一次就好了),那么我们考虑一条边\((u,v)\)的贡献(也就是钦定要经过这条边的最长路)为\(f[u]+1+g[v]\),那么最长路的问题就变成了求边贡献的最大值
这个时候,考虑\(S\)到\(T\)的一个割(注意:这里不一定是最小割!只是一个普通的割即可),那么根据其定义,所有从\(S\)到\(T\)的路径必定经过割集中的最少一条边,也就是说,如果我们将\(f[u]+1+g[v]\)看成原图中\((u,v)\)这条边的边权,将\((S,i)\)的边权看成\(f[i]\),\((i,T)\)的边权看成\(g[i]\),割集中边权的最大值便是我们需要的答案
那么现在我们只要知道删掉一个点之后,剩余图中\(S\)到\(T\)的一个割就可以知道删掉这个点的答案了,至此我们已经完成了问题的转化,现在的问题是我们怎么维护这个割集
我们考虑用一个数据结构来快速获得边权最大值(线段树或者堆都ok)
假设一开始我们先把所有的\((i,T)\)的边全部断掉(这显然是一个可行的割),也就是先将所有的\(g[i]\)丢进数据结构里面,现在考虑删掉一个点\(x\)的影响:所有拓扑序在\(x\)之后的点的\(f\)值可能会被影响,所有拓扑序在\(x\)之前的点的\(g\)值可能会被影响,这个时候为了保证正确性我们应该将当前割集中可能会被改变边权的边全部删掉
但是这样怎么保证当前最大值一定在数据结构里面呢?这里需要一点关于操作顺序的技巧,下面先将过程讲一下:
我们考虑按照拓扑序从小到大依次计算删除这个点之后的最长路,对于当前枚举到的点\(x\),我们进行如下操作:
1、将\((x,T)\)这条边删掉,将所有的\((u,x)\)删掉(如果本来就没有就不进行操作)
2、统计当前割集中边权的最大值,更新答案
3、将\((S,x)\)这条边加入割集,将所有的\((x,v)\)加入割集
具体一点的话就是,首先\(1\)操作就是将割集中所有与\(x\)有关的边全部删掉,\(2\)不用说,关键是\(3\)操作,为什么我们还原割集的时候不是将\(1\)操作中删除的边加回进去呢?
因为我们是按照拓扑序从小到大删点的,根据我们前面分析出来的删点影响,在删除后面的点的时候,\(g[x]\)是可能会被影响的值(转移过来的边可能会被删掉),因此为了保证正确性我们不能将其留在割集中,同时为了保证这是一个割集,相对应的边权不会被影响到并且效果类似的\((S,x)\)就应该被加入割集,同样的道理\((u,x)\)的边权中的\(g[x]\)可能会被影响所以要删掉,然后为了保证一定是一个割集所以要加入\((x,v)\)这类边
那么会不会出现有的边的贡献作为答案没有被统计的情况呢?这个。。是不会的因为如果说\((u,x)\)这类边的贡献是答案的话,一定会在前面被计算到
然后这题就十分愉快地做完啦ovo时间复杂度\(O(nlogn)\)
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=500010,M=1000010,SEG=N*4,inf=2147483647;
struct xxx{
int y,nxt;
}a[M*2];
queue<int> q;
int h1[N],h[N],in[N],out[N],f[N],g[N];
int rec[N];
int n,m,tot,ans,ansnode;
namespace Seg{/*{{{*/
int ch[SEG][2],mx[SEG],cnt[SEG];
int n,tot;
void pushup(int x){mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);}
void _build(int x,int l,int r){
mx[x]=-1;
if (l==r) return;
int mid=l+r>>1;
ch[x][0]=++tot; _build(ch[x][0],l,mid);
ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
}
void build(int _n){tot=1; n=_n; _build(1,1,n);}
void _insert(int x,int d,int lx,int rx,int delta){
if (lx==rx){
cnt[x]+=delta;
if (cnt[x]>0) mx[x]=lx;
else cnt[x]=0,mx[x]=-1;
return;
}
int mid=lx+rx>>1;
if (d<=mid) _insert(ch[x][0],d,lx,mid,delta);
else _insert(ch[x][1],d,mid+1,rx,delta);
pushup(x);
}
void insert(int d,int delta){_insert(1,d,1,n,delta);}
int query(){return mx[1];}
}/*}}}*/
void add(int x,int y){
a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;
a[++tot].y=x; a[tot].nxt=h1[y]; h1[y]=tot;
}
void prework(){
int u,v;
while (!q.empty()) q.pop();
for (int i=1;i<=n;++i)
if (!in[i]) q.push(i),f[i]=0;
rec[0]=0;
while (!q.empty()){
v=q.front(); q.pop(); rec[++rec[0]]=v;
for (int i=h[v];i!=-1;i=a[i].nxt){
u=a[i].y;
f[u]=max(f[u],f[v]+1);
--in[u];
if (!in[u]) q.push(u);
}
}
for (int i=1;i<=n;++i)
if (!out[i]) q.push(i),g[i]=0;
while (!q.empty()){
v=q.front(); q.pop();
for (int i=h1[v];i!=-1;i=a[i].nxt){
u=a[i].y;
g[u]=max(g[u],g[v]+1);
--out[u];
if (!out[u]) q.push(u);
}
}
}
void solve(){
int x,u,tmp;
ans=inf; ansnode=0;
Seg::build(n+1);
for (int i=1;i<=n;++i) Seg::insert(g[i]+1,1);
for (int i=1;i<=n;++i){
x=rec[i];
Seg::insert(g[x]+1,-1);
for (int j=h1[x];j!=-1;j=a[j].nxt){
u=a[j].y;
Seg::insert(f[u]+1+g[x]+1,-1);
}
tmp=Seg::query();
if (ans>tmp)
ans=tmp,ansnode=x;
Seg::insert(f[x]+1,1);
for (int j=h[x];j!=-1;j=a[j].nxt){
u=a[j].y;
Seg::insert(f[x]+1+g[u]+1,1);
}
}
printf("%d %d\n",ansnode,ans-1);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,y;
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
memset(h1,-1,sizeof(h1));
tot=0;
for (int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
add(x,y);
++in[y]; ++out[x];
}
prework();
solve();
}
【bzoj3832】Rally的更多相关文章
- 【BZOJ-3832】Rally 拓扑序 + 线段树 (神思路题!)
3832: [Poi2014]Rally Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 168 Solved: ...
- 【BZOJ3832】[POI2014]Rally(拓扑排序,动态规划)
[BZOJ3832][POI2014]Rally(拓扑排序,动态规划) 题面 BZOJ,权限题 洛谷 题解 这题好强啊,感觉学了好多东西似的. 首先发现了一个图画的很好的博客,戳这里 然后我来补充一下 ...
- Python高手之路【六】python基础之字符串格式化
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【调侃】IOC前世今生
前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...
- Python高手之路【三】python基础之函数
基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...
- Python高手之路【一】初识python
Python简介 1:Python的创始人 Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种解释型.面向对象.动态数据类型的高级程序设计语言,由荷兰人Guido ...
随机推荐
- 如何寻找无序数组中的第K大元素?
如何寻找无序数组中的第K大元素? 有这样一个算法题:有一个无序数组,要求找出数组中的第K大元素.比如给定的无序数组如下所示: 如果k=6,也就是要寻找第6大的元素,很显然,数组中第一大元素是24,第二 ...
- Extreme Learning Machine 翻译
本文是作者这几天翻译的一篇经典的ELM文章,是第一稿,所以有很多错误以及不足之处. 另外由于此编辑器不支持MathType所以好多公式没有显示出来,原稿是word文档. 联系:250101249@qq ...
- Cocos2dx源码赏析(2)之渲染
Cocos2dx源码赏析(2)之渲染 这篇,继续从源码的角度来跟踪下Cocos2dx引擎的渲染过程,以此来梳理下Cocos2dx引擎是如何将精灵等元素显示在屏幕上的. 从上一篇对Cocos2dx启动流 ...
- Ajax请求返回Error:200无数据的解决方法
先看代码 $.ajax({ type:"GET", url:"https://****/charts/data/genre2.json", dataType:& ...
- Kubernetes探索学习001--Centos7.6使用kubeadm快速部署Kubernetes集群
Centos7.6使用kubeadm快速部署kubernetes集群 为什么要使用kubeadm来部署kubernetes?因为kubeadm是kubernetes原生的部署工具,简单快捷方便,便于新 ...
- Final阶段版本控制报告
版本控制代码及文档要求 在coding.net版本控制; 公开项目,教师.专家.其他同学可以不注册源代码.在此公布git地址. 报告beta阶段2周中,项目的版本控制情况,不包括未在coding.ne ...
- 团队项目M1阶段个人反思
郑培蕾: 作为项目的PM,我前期的工作还是有很大的缺陷的,因为没有在开发之前对项目进行一个合理的评估,所以后来分配任务的时候就很不科学, 而且任务分配的比较粗糙,没有细化到每个人每天应该做什么,这就导 ...
- 团队项目开题Scrum Meeting报告
团队项目开题Scrum Meeting报告 在10月30号星期四的晚上我们团队找到了给我们代码的王翊学长,由学长给我们讲解了他编写IOS平台上北航MOOC系统的架构和思路, 因为我们团队没有苹果公司的 ...
- 编程之法section II: 2.1 求最小的k个数
====数组篇==== 2.1 求最小的k个数: 题目描述:有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低. 解法一: 思路:快排后输出前k个元素,O(nlogn). writer: zz ...
- ssh框架配置数据源 数据库连接没有正常释放
通过多天的改bug 对数据源这个东西了解多了.. 我发现 spring+hibernate下 申请数据库连接是在一个action方法内 也就是说 action 里面有三个 service方 ...