【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 ...
随机推荐
- 高可用OpenStack(Queen版)集群-2.基础服务
参考文档: Install-guide:https://docs.openstack.org/install-guide/ OpenStack High Availability Guide:http ...
- NO.3_1:自学python之路------番外:第三方库安装、numpy
引言 Python因为pip的存在,使得第三方库的发布和获取都比较方便.并且Python对跨平台的支持,使得其相较于C++,Java更加方便使用.在本文中,将会介绍在Windows中安装第三方库的方法 ...
- Bitcoin Core P2P网络层
目录 数据结构 节点发现和节点连接 地址管理 节点发现 节点连接 插口(Sockets)和消息 Socket线程 (net.cpp) 消息线程 ProcessMessages (net_process ...
- Rabbitmq安装及启动 MAC系统
1.安装 brew install rabbitmq 2.启动及关闭RabbitMQ服务 前台启动 sudo ./rabbitmq-server 或 sudo su/usr/local/Cell ...
- ms cms
很多开源CMS,都是半开源或假开源. 看看微软的CMS怎么样吧.这么著名的CMS,下载网址不好找. https://orchard.codeplex.com/SourceControl/latest
- c#窗体移动与窗体阴影效果
//步骤//1.导入代码//2.事件中添加form_1mousedown函数//3.在load函数中定义AnimateWindow语句,注意有两个引用.//4.DllImport若有错误,按shift ...
- 灵悟礼品网上专卖店——画出E-R图
一.小组成员: 洪雪意(产品负责人) 陈淑筠(Master) 二.组内人员任务情况 计划完成的任务的第三个模块:分析并建立数据库 已完成的任务: 任务的第三个模块: 陈淑筠(完成任务1):画出商品资料 ...
- 蜗牛慢慢爬 LeetCode 6. ZigZag Conversion [Difficulty: Medium]
题目 The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows li ...
- win10频繁提示证书即将过期怎么办
最近几天每次开机都会提示许可证即将过期 ”Windows+R”打开“运行”窗口,输入“slmgr.vbs -xpr”并点击“确定”,弹出的窗口确实显示过期时间在本月1.29过期 百度各种激活方法后,发 ...
- 使用JavascriptExecutor改变页面元素
如下如html的页面代码 <html> <body> <input type="text" name="text" value=& ...