【BZOJ3832】[POI2014]Rally(拓扑排序,动态规划)

时间:2022-11-13 08:10:25

【BZOJ3832】[POI2014]Rally(拓扑排序,动态规划)

题面

BZOJ,权限题

洛谷

题解

这题好强啊,感觉学了好多东西似的。

首先发现了一个图画的很好的博客,戳这里

然后我来补充一下这题到底怎么做。

首先这个图是一个\(DAG\),我们对其进行拓扑排序,设\(f[i]\)表示以\(i\)开头的最长链长度,\(g[i]\)表示以\(i\)结尾的最长链长度,那么经过某条边\(u\rightarrow v\)的边贡献的最长路的贡献就是\(g[u]+f[v]+1\)。

我们发现,如果我们删除某一个点\(x\),那么我们必定能够把整个图分成两个部分,左侧我们认为是拓扑序小于\(x\)的点集,右侧是拓扑序大于\(x\)的点集,那么最终的答案显然是从左侧的某一个点连向右侧的某一个点能够贡献的最长链。所以我们只需要动态的维护左侧连向右侧的边的贡献就好了。我们先假设所有点都在右侧,按照拓扑序依次把所有点移到左侧就好了。我们可以直接在这个过程中统计答案。首先我们把所有左侧连向当前点的边的贡献全部删掉,然后统计一下答案,然后再把这个点连向右侧的边的贡献全部加入进来。当然,不仅仅只有边的贡献,显然\(f,g\)两个数组可以产生贡献,左侧的点产生\(g\)的贡献,右侧产生\(f\)的贡献,也和边的贡献一起丢进什么数据结构维护一下就好了。因为每条边只会加一次,删一次,所以复杂度是\(O((n+m)log)\)的。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
#define MAX 500500
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Heap
{
priority_queue<int> Q1,Q2;
void push(int x){Q1.push(x);}
void del(int x){Q2.push(x);}
bool empty(){while(!Q2.empty()&&Q1.top()==Q2.top())Q1.pop(),Q2.pop();return Q1.empty();}
int top(){if(empty())return 1e9;return Q1.top();}
}S;
int n,m,ans1=1e9,ans2;
struct Line{int v,next;}e[MAX<<2];
int h[MAX],cnt=1,dg[MAX];
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int Q[MAX],f[MAX],g[MAX];
void Topsort()
{
int he=1,t=0;
for(int i=1;i<=n;++i)if(!dg[i])Q[++t]=i;
while(he<=t)
{
int u=Q[he++];
for(int i=h[u];i;i=e[i].next)
if(i&1)if(!--dg[e[i].v])Q[++t]=e[i].v;
}
for(int u=1;u<=n;++u)
for(int i=h[Q[u]];i;i=e[i].next)
if(i&1)g[e[i].v]=max(g[e[i].v],g[Q[u]]+1);
for(int u=n;u>=1;--u)
for(int i=h[Q[u]];i;i=e[i].next)
if(i&1)f[Q[u]]=max(f[Q[u]],f[e[i].v]+1);
}
int main()
{
n=read();m=read();
for(int i=1,u,v;i<=m;++i)u=read(),v=read(),Add(u,v),Add(v,u),++dg[v];
Topsort();
for(int i=1;i<=n;++i)S.push(f[i]);
for(int j=1;j<=n;++j)
{
int u=Q[j];S.del(f[u]);
for(int i=h[u];i;i=e[i].next)
if(!(i&1))S.del(f[u]+g[e[i].v]+1);
int d=S.top();S.push(g[u]);
if(d<ans1)ans1=d,ans2=u;
for(int i=h[u];i;i=e[i].next)
if(i&1)S.push(g[u]+f[e[i].v]+1);
}
printf("%d %d\n",ans2,ans1);
return 0;
}

【BZOJ3832】[POI2014]Rally(拓扑排序,动态规划)的更多相关文章

  1. BZOJ3832&colon; &lbrack;Poi2014&rsqb;Rally&lpar;拓扑排序 堆&rpar;

    题意 题目链接 Sol 最直观的思路是求出删除每个点后的最长路,我们考虑这玩意儿怎么求 设\(f[i]\)表示以\(i\)结尾的最长路长度,\(g[i]\)表示以\(i\)开始的最长路长度 根据DAG ...

  2. BZOJ3832&lbrack;Poi2014&rsqb;Rally——权值线段树&plus;拓扑排序

    题目描述 An annual bicycle rally will soon begin in Byteburg. The bikers of Byteburg are natural long di ...

  3. 【BZOJ-3832】Rally 拓扑序 &plus; 线段树 (神思路题!)

    3832: [Poi2014]Rally Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 168  Solved:  ...

  4. bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划

    一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V ...

  5. Luogu3953 NOIP2017逛公园(最短路&plus;拓扑排序&plus;动态规划)

    跑一遍dij根据最短路DAG进行拓扑排序,按拓扑序dp即可.wa了三发感觉非常凉. #include<iostream> #include<cstdio> #include&l ...

  6. BZOJ3832 &lbrack;Poi2014&rsqb;Rally 【拓扑序 &plus; 堆】

    题目链接 BZOJ3832 题解 神思路orz,根本不会做 设\(f[i]\)为到\(i\)的最长路,\(g[i]\)为\(i\)出发的最长路,二者可以拓扑序后\(dp\)求得 那么一条边\((u,v ...

  7. BZOJ3832 &colon; &lbrack;Poi2014&rsqb;Rally

    f[0][i]为i出发的最长路,f[1][i]为到i的最长路 新建源汇S,T,S向每个点连边,每个点向T连边 将所有点划分为两个集合S与T,一开始S中只有S,其它点都在T中 用一棵线段树维护所有连接属 ...

  8. 并不对劲的bzoj3832&colon; &lbrack;Poi2014&rsqb;Rally

    传送门-> 这题的原理看上去很神奇. 称拓扑图中入度为0的点为“起点”,出度为0的点为“终点”. 因为“起点”和“终点”可能有很多个,算起来会很麻烦,所以新建“超级起点”S,向所有点连边,“超级 ...

  9. 【BZOJ1471】不相交路径 题解(拓扑排序&plus;动态规划&plus;容斥原理)

    题目描述 在有向无环图上给你两个起点和终点分别为$a,b,c,d$.问有几种路径方案使得能从$a$走到$b$的同时能从$c$走到$d$,且两个路径没有交点. $1\leq n\leq 200,1\le ...

  10. &lbrack;luogu3573 POI2014&rsqb; RAJ-Rally &lpar;拓扑排序 权值线段树&rpar;

    传送门 Solution 在DAG中我们可以\(O(n)\)预处理\(Ds(u)\)表示从u表示以s为起点的最长路\(Dt(u)\)表示以u为终点的最长路,那么经过\((u,v)\)的最长路即为\(D ...

随机推荐

  1. ESXi5&period;5下的Centos7虚机配置静态IP

    使用的是osboxes.org上下载的已安装centos7 image, 在启动后, ifconfig不能看到网卡, 需要关机后在ESXi客户端编辑虚机, 删除网卡, 保存, 添加网卡, 网卡类型选择 ...

  2. Search Insert Position

    int searchInsert(int* nums, int numsSize, int target) { ; ); ; int mid; while(low<=high){ mid=(lo ...

  3. iOS开发网络篇—NSURLConnection基本使用(一)

      一.NSURLConnection的常用类 (1)NSURL:请求地址 (2)NSURLRequest:封装一个请求,保存发给服务器的全部数据,包括一个NSURL对象,请求方法.请求头.请求体.. ...

  4. 查询数据表,去除符合某些条件的记录,没有自动增长列(not exists&rpar;

    select distinct ccode,isnull(cexch_name,''),N'',N'',N'2014.03',0,1,1,1,12 from RP_bankrecp where not ...

  5. mao&sol;reduce实现求平均值

    import java.io.*; import java.util.*; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io. ...

  6. C&num;解leetcode 53&period;Maximum Subarray

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  7. android textview字体加粗 Android studio最新水平居中和垂直居中

    android textview字体加粗 Android studio最新水平居中和垂直居中 Android中字体加粗在xml文件中使用android:textStyle=”bold”但是不能将中文设 ...

  8. Python之旅:并发编程之多线程理论部分

    一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 车间负责把资源整合 ...

  9. 【问题解决】增加https后 phpcms 分页错误

    https://m.cnbuses.com/m.cnbuses.com/index.php?page=2查看分页方法 function pages()中有个pageurl 查看该方法,发现有类似htt ...

  10. 7&period;15&semi;linux命令

    麦克维瀑布 https://farm5.staticflickr.com/4269/34749113172_d6c1ba274a_k.jpg ----------------------------- ...