并不对劲的bzoj3832: [Poi2014]Rally
传送门->
这题的原理看上去很神奇。
称拓扑图中入度为0的点为“起点”,出度为0的点为“终点”。
因为“起点”和“终点”可能有很多个,算起来会很麻烦,所以新建“超级起点”S,向所有点连边,“超级终点”T,所有点向它连边。这样原图中的最长路就是新图中的最长路-2。
dis[a->b]表示a到b的距离。
对于一个拓扑图而言,它的一个割集中肯定有一条边在最长路上。对于每条边,可以将dis[S->该边起点]和dis[该边终点->T]算出,那么该边所在路径中的最长的一个就是dis[S->该边起点]+dis[该边终点->T]+1。将该边边权设为它。这样一来,最长路就是该图随便一个割集的边权最大值。
删掉一个点,就可以看成删掉这个点的所有出边。但是这样就有些问题了:所有能走到这条边的边和这条边能走到的所有边都会因为这条边删掉而受影响,要是把所有的影响都算出来,想必是不行的。这时就有一个看似可行的方法了:在删掉这个点的所有出边的图中求一个只包含与这些边不互达的边的割集,取这个割集中的边权最大值。会发现那个割集就是原图中由这个点的所有出边和一些与它不互达的边组成的一个割集。
会不会出现不互达的边不够用的情况?先把拓扑图按最长路分好层(浅蓝色的线)。

这样的话,就不会存在右->左的边。
也就是说,图中所有红边和所有蓝边都是不互达的。而删掉所有红边和所有蓝边后,就不能从左边走到右边了。这样就形成了一个割集。答案就是所有蓝边的边权最大值。
如果这个删掉的点后图变成两部分怎么办?想必是不可能的,因为对于每一个点,都有 S->该点 和 该点->T 的边,所以只要不删S、T就不会将图分成几部分。肯定会有上图中蓝边那样的边存在的。
那么问题就变成了对于每个点,求出所有与它不互达的边权的最大值,再对于所有点取最小值就行了!
好吧,这并没有把问题简化多少,至少变得相对可做了。
那么可以考虑递推。按照拓扑序枚举要删掉的点,每次将当前点变成下一个时,新的那个点的所有入边要删去,上一个点的所有出边要加入。
这是为什么呢?因为上一个状态是删掉上一个点的图,计入答案的是割集中不包括与上一个点可达的边的边权。加入上一个点的所有出边后,就刚好凑成了一个割集。此时计入答案的是原图的一个割集。但是我们要求的是删除新的点的割集,所以就要删除所有连向新的点的边。这时不会有其它与能走到该点的边。这是因为能走到该点的边的起点、终点的拓扑序都小于该点(终点是该点的边刚刚已经被删去了,不考虑)。也就是说,所有这些边的终点之前已经被考虑过了,它们的入边已经全部被删除了。而该点能到达的边的起点的拓扑序在该点之后,还没有被加入,所有不用考虑。
每次删除新的点的所有出边,会多删除吗?想必是不会的。新的点的所有入边的起点在拓扑序中都比该点靠前,所以所有入边之前都被加入了。
用什么数据结构维护呢?看上去需要支持取最大值、插入、删除,堆似乎不错。
刚刚证明了这种方法是可行的,但至于具体是怎么想出来的,我能说是去看某个大佬的博客吗?
#include<algorithm>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define re register
#define maxn 500010
#define maxm 2000010
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(isdigit(ch)==0 && ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(int x)
{
int f=0;char ch[20];
if(!x){putchar('0'),putchar(' ');return;}
if(x<0){putchar('-');x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar(' ');
}
int fir[2][maxn],nxt[2][maxm],v[2][maxm],id[2][maxm],cnt[2];//0:roads; 1:back roads;
int S,T,n,m,mx,mxnd;
int q[maxn],hd,tl,dis[2][maxn],in[maxn];
void ade(int u1,int v1,int id1,int f){v[f][cnt[f]]=v1,id[f][cnt[f]]=id1,nxt[f][cnt[f]]=fir[f][u1],fir[f][u1]=cnt[f]++;}
priority_queue<int>yes,no;
void inq(int x){yes.push(x);while(!no.empty()&&yes.top()==no.top())yes.pop(),no.pop();}
void deq(int x){no.push(x);while(!no.empty()&&yes.top()==no.top())yes.pop(),no.pop();}
int top(){while(!no.empty()&&yes.top()==no.top())yes.pop(),no.pop();return yes.top();}
int tmp[maxn],cntt;/*
void print()
{
cout<<"heap:"<<endl;
while(!no.empty()&&yes.top()==no.top())yes.pop(),no.pop();
while(!yes.empty())cout<<yes.top()<<" ",tmp[++cntt]=yes.top(),yes.pop();
while(cntt)yes.push(tmp[cntt--]);cout<<endl;
}*/
int main()
{
memset(fir,-1,sizeof(fir));
n=read(),m=read();
rep(i,1,m){int x=read(),y=read();ade(x,y,i,0),ade(y,x,i,1);in[y]++;}S=0,T=n+1;
rep(i,1,n)ade(S,i,i+m,0),ade(i,S,i+m,1),ade(i,T,i+m,0),ade(T,i,i+m,1),in[i]++,in[T]++;
q[++tl]=S;
while(hd<tl)
{
int u=q[++hd];
for(int k=fir[0][u];k!=-1;k=nxt[0][k])
{
int vv=v[0][k];in[vv]--;
if(in[vv]==0){q[++tl]=vv;}
}
}
rep(i,1,tl)
{
int u=q[i];
for(int k=fir[0][u];k!=-1;k=nxt[0][k])
{
int vv=v[0][k];
dis[0][vv]=max(dis[0][u]+1,dis[0][vv]);
}
}
dwn(i,tl,1)
{
int u=q[i];
for(int k=fir[0][u];k!=-1;k=nxt[0][k])
{
int vv=v[0][k];
dis[1][u]=max(dis[1][vv]+1,dis[1][u]);
}
}
mx=2147483647;
rep(i,2,tl-1)
{
int u=q[i],pu=q[i-1];
for(int k=fir[0][pu];k!=-1;k=nxt[0][k])
{
int vv=v[0][k];
inq(dis[0][pu]+dis[1][vv]+1);
}
for(int k=fir[1][u];k!=-1;k=nxt[1][k])
{
int vv=v[1][k];
deq(dis[0][vv]+dis[1][u]+1);
}
if(mx>top())mx=top(),mxnd=u;
}
write(mxnd),write(mx-2);
return 0;
}
/*
6 5
1 3
1 4
3 6
3 4
4 5
*/
并不对劲的bzoj3832: [Poi2014]Rally的更多相关文章
- BZOJ3832[Poi2014]Rally——权值线段树+拓扑排序
题目描述 An annual bicycle rally will soon begin in Byteburg. The bikers of Byteburg are natural long di ...
- BZOJ3832 [Poi2014]Rally 【拓扑序 + 堆】
题目链接 BZOJ3832 题解 神思路orz,根本不会做 设\(f[i]\)为到\(i\)的最长路,\(g[i]\)为\(i\)出发的最长路,二者可以拓扑序后\(dp\)求得 那么一条边\((u,v ...
- BZOJ3832 : [Poi2014]Rally
f[0][i]为i出发的最长路,f[1][i]为到i的最长路 新建源汇S,T,S向每个点连边,每个点向T连边 将所有点划分为两个集合S与T,一开始S中只有S,其它点都在T中 用一棵线段树维护所有连接属 ...
- BZOJ3832: [Poi2014]Rally(拓扑排序 堆)
题意 题目链接 Sol 最直观的思路是求出删除每个点后的最长路,我们考虑这玩意儿怎么求 设\(f[i]\)表示以\(i\)结尾的最长路长度,\(g[i]\)表示以\(i\)开始的最长路长度 根据DAG ...
- 【BZOJ3832】[POI2014]Rally(拓扑排序,动态规划)
[BZOJ3832][POI2014]Rally(拓扑排序,动态规划) 题面 BZOJ,权限题 洛谷 题解 这题好强啊,感觉学了好多东西似的. 首先发现了一个图画的很好的博客,戳这里 然后我来补充一下 ...
- 【BZOJ-3832】Rally 拓扑序 + 线段树 (神思路题!)
3832: [Poi2014]Rally Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 168 Solved: ...
- 3832: [Poi2014]Rally
3832: [Poi2014]Rally 链接 分析: 首先可以考虑删除掉一个点后,计算最长路. 设$f[i]$表示从起点到i的最长路,$g[i]$表示从i出发到终点的最长路.那么经过一条边的最长路就 ...
- [POI2014]Rally
OJ题号:BZOJ3832.洛谷3573 思路: 建立超级源汇$S$和$T$,DP求出分别以$S$和$T$为源点的最长路$diss$和$dist$. 对于每条边$i$,设定一个权值$w_i=diss_ ...
- 【bzoj3832】Rally
Portal -->bzoj3832 Description 给你一个DAG,每条边长度都是\(1\),请找一个点满足删掉这个点之后剩余图中的最长路最短 Solution 这题的话感觉 ...
随机推荐
- CSU 1307 最短路+二分
题目大意: 帮忙找到一条a到b的最短路,前提是要保证路上经过的站点的最大距离尽可能短 这道题居然要用到二分...完全没去想过,现在想想求最大距离的最小值确实是... 这里不断二分出值代入spfa()或 ...
- 后缀排序(codevs 1500)
题目描述 Description 天凯是MIT的新生.Prof. HandsomeG给了他一个长度为n的由小写字母构成的字符串,要求他把该字符串的n个后缀(suffix)从小到大排序. 何谓后缀?假设 ...
- [NOIP2001] 提高组 洛谷P1027 Car的旅行路线
题目描述 又到暑假了,住在城市A的Car想和朋友一起去城市B旅游.她知道每个城市都有四个飞机场,分别位于一个 矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单 ...
- 【BZOJ1237】配对(贪心,DP)
题意:有n个a[i]和b[i],调整顺序使abs(a[i]-b[i])之和最小,但a[i]<>b[i].保证所有 Ai各不相同,Bi也各不相同. 30%的数据满足:n <= 104 ...
- 汕头市赛srm8 C-3
n<=100000个点m<=300000条边有权无向联通图,给出K<=10000个特殊点求K个点中任意两点最短路的最小值. 方法一:K小,随便搞.先构造最短路树,在最短路树上Dijk ...
- C语言基本概念之表达式
原文地址:http://blog.csdn.net/astrotycoon/article/details/50857326 [侵删] 什么是表达式(表达式的定义)? 对于表达式的定义,好像从来没有人 ...
- 0c-适配 iOS 11
参考路径:https://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=2653579210&idx=1&sn=d5ea8d46c ...
- Spring的Web MVC框架
以下内容引用自http://wiki.jikexueyuan.com/project/spring/web-mvc-framework.html: Spring web MVC框架提供了模型-视图-控 ...
- Android切图注意事项
1.App Logo大小共五种: 48*48 72*72 96*96 144*144 192*192 2. App启动页所需尺寸: 320×480 480×800 720*1280 1080*1920 ...
- Deepin-安装QQ音乐(Windows程序)
打开命令行,输入: sudo apt-get install wine 安装完成后,下载QQ音乐的安装包 然后安装 示例:wine xx.exe 实例:wine QQMusic.exe 安装完成,启动 ...