洛谷 P3573 [POI2014]RAJ-Rally 解题报告
P3573 [POI2014]RAJ-Rally
题意:
给定一个\(N\)个点\(M\)条边的有向无环图,每条边长度都是\(1\)。
请找到一个点,使得删掉这个点后剩余的图中的最长路径最短。
输入输出格式
输入格式:
第一行包含两个正整数\(N\),\(M\),表示点数、边数。
接下来\(M\)行每行包含两个正整数\(A_i,B_i\),表示\(A_i\)到\(B_i\)有一条边。
输出格式:
包含一行两个整数\(x,y\),用一个空格隔开,\(x\)为要删去的点,\(y\)为删除x$后图中的最长路径的长度,如果有多组解请输出任意一组。
说明:
\(N,M(2 \le N \le 500000,1 \le M \le 1000000)\)
好神仙的一道题目!
一般来说一些删边删点的东西在统计统计信息什么的在图上都比较麻烦,我们应该找一找这个题的特殊性
很容易发现,重点在这个图是DAG。
有了DAG,我们可以\(O(n)\)求出单源点最长路什么的
然而这个图的最长路咋求呢?其实这个不难,统计通过每条边的最长路,取最大值就行了
设\(diss_i\)表示以\(i\)为开头的最长路,\(dist_i\)表示以\(i\)为结尾的最长路,为起点的反向跑一遍就可以得到
通过某条边\(E=(u,v)\)的最长路等价于\(dist_u+diss_v+1\)
topo图还有一个性质,按照topo序取出一部分连续的点作为\(S\)集,剩下的作为\(T\)集,则两个集合的相互连边只有一些\(S\)到\(T\)的
为了方便,节点编号就是topo序,红边为\(S\)连向\(T\)的边
这启发我们按照拓扑序进行删点,我们先假设所有的点在\(T\)集,这样最长路就是\(max diss_i\)
我们按topo序拿走点,删掉有关贡献的边,统计答案,加入有关贡献的边,然后加入\(S\)集
这样说起来一点也不清楚,我们结合图形说明
现在正在删点4,看看有那些边可以作为答案。
首先\(S\)集合里面的边的最长长度,但不可以跨越两个集合即 \(max_{i \in S} dist_i\),当然4的不算
然后跨越\(S,T\)集合的边即 \(max_{E(u,v),u \in S,v \in T} dist_u+diss_v+1\)
最后是集合\(T\)的,其实也差不多,不赘述了
我们首先在\(T\)集合的只有最后一种的答案,发现第一种的答案可以在把点扔进\(S\)的时候更新,而多余的\(T\)的答案可以在每次删点时删掉
第二种边其实也好统计,在点进去的时候出边都放进答案,当这个出边对的点进入\(S\)的时候把边的答案去掉
这么说可能还是有点抽象,还是拿4举个例子
第一步,删去\(diss_4\)
第二步,删去\(diss_4+dist_{1/2/3}+1\)这三个
第三步,统计最大值
第四步,加入\(dist_4+diss_{6/7}+1\)这两个
第五步,加入\(dist_4\)
关于这些操作,因为边权很小,所以我们可以拿权值线段树维护,也可以拿堆维护
其实思想上我说得也不算清楚,只是大概把过程讲清楚了
Code:
#include <cstdio>
#include <vector>
const int N=1e6+10;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
std::vector <int > To[N];
int q[N],n,m,in[N],topo[N],tot;
void toposort()
{
int l=1,r=0;
for(int i=1;i<=n;i++)
if(!in[i]) topo[++tot]=i,q[++r]=i;
while(l<=r)
{
int u=q[l++];
for(int i=head[u];i;i=Next[i])
{
int v=to[i];
--in[v];
if(!in[v]) q[++r]=v,topo[++tot]=v;
}
}
}
int diss[N],dist[N];
#define ls ch[now][0]
#define rs ch[now][1]
int max(int x,int y){return x>y?x:y;}
void DP()
{
for(int k=1;k<=n;k++)
{
int u=topo[k];
for(int i=head[u];i;i=Next[i])
{
int v=to[i];
dist[v]=max(dist[v],dist[u]+1);
}
}
for(int k=n;k;k--)
{
int u=topo[k];
for(int i=0;i<To[u].size();i++)
{
int v=To[u][i];
diss[v]=max(diss[v],diss[u]+1);
}
}
}
void init()
{
scanf("%d%d",&n,&m);
for(int u,v,i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add(u,v),++in[v],To[v].push_back(u);
}
toposort();
DP();
}
int ch[N<<2][2],sum[N<<2],root;
void change(int &now,int l,int r,int pos,int delta)
{
if(!now) now=++tot;
if(l==r) {sum[now]+=delta;return;}
int mid=l+r>>1;
if(pos<=mid) change(ls,l,mid,pos,delta);
else change(rs,mid+1,r,pos,delta);
sum[now]=sum[ls]+sum[rs];
}
int query(int now,int l,int r)
{
if(l==r) return l;
int mid=l+r>>1;
if(sum[rs]) return query(rs,mid+1,r);
else return query(ls,l,mid);
}
void work()
{
tot=0;int mx,id,ans=0x7fffffff;
for(int i=1;i<=n;i++)
change(root,0,n,diss[i],1);
for(int i=1;i<=n;i++)
{
int now=topo[i];
change(root,0,n,diss[now],-1);
for(int j=0;j<To[now].size();j++)
{
int v=To[now][j];
change(root,0,n,diss[now]+dist[v]+1,-1);
}
if((mx=query(root,0,n))<ans) ans=mx,id=now;
for(int j=head[now];j;j=Next[j])
{
int v=to[j];
change(root,0,n,dist[now]+diss[v]+1,1);
}
change(root,0,n,dist[now],1);
}
printf("%d %d\n",id,ans);
}
int main()
{
init(),work();
return 0;
}
2018.9.7
洛谷 P3573 [POI2014]RAJ-Rally 解题报告的更多相关文章
- 洛谷_Cx的故事_解题报告_第四题70
1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h> struct node { long x,y,c; ...
- 洛谷 P2317 [HNOI2005]星际贸易 解题报告
P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...
- 洛谷 P3802 小魔女帕琪 解题报告
P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...
- 洛谷 P2606 [ZJOI2010]排列计数 解题报告
P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...
- 洛谷1303 A*B Problem 解题报告
洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...
- 【刷题】洛谷 P3573 [POI2014]RAJ-Rally
题目描述 An annual bicycle rally will soon begin in Byteburg. The bikers of Byteburg are natural long di ...
- 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告
[USACO13OPEN]照片Photo 题目描述 农夫约翰决定给站在一条线上的\(N(1 \le N \le 200,000)\)头奶牛制作一张全家福照片,\(N\)头奶牛编号\(1\)到\(N\) ...
- 洛谷 P1379 八数码难题 解题报告
P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...
- NOIP2015 D2T3 洛谷2680 BZOJ4326 运输计划 解题报告
前言:个人认为这是历年NOIP中比较简单的最后一题了,因此将自己的思路与大家分享. 题目大意: 给一棵无根树,给出m条路径.允许将树上的一条边的权值改为0.求m条路径长度最大值的最小值.n,m< ...
随机推荐
- HDU2837 Calculation(扩展欧拉定理)
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission( ...
- ethereum(以太坊)(五)--Bool
pragma solidity ^0.4.0; contract Bool{ uint num1 = 100; uint num2 = 200; bool _c = true; // &&am ...
- dts--framework(一)
dts 大体框架 framework 定义类 定义方法 tests framework调用所需要的函数 ./dpdk/usertools/cpu_layout.py /sys/devices/syst ...
- FreeBSD--网络配置
配置网口:ifconfig |less dc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 i ...
- jQuery检测判断复选框是否被选中了的几种方法
方法一:if ($("#checkbox-id")get(0).checked) { // do something} 方法二:if($('#checkbox-id').is ...
- python 函数 闭包 (节省内存空间 html 获取网页的源码)
#闭包:嵌套函数,内部函数调用外部函数的变量 # def outer(): # a = 1 # def inner(): # print(a) # inner() # outer() def oute ...
- C语言指针篇(一)指针与指针变量
指针 1. 什么是指针? 2. 指针可不可怕? 3. 指针好不好玩? 4. 怎么学好指针? C语言是跟内存打交道的语言,指针就是内存地址.指针无处不在,指针并不可怕,相反,等你学到一定程 ...
- Immutable
Immutable 参考文章 https://zhuanlan.zhihu.com/p/20295971?columnSlug=purerender
- Hibernate---架构
Hibernate 架构是分层的,作为数据访问层,你不必知道底层 API .Hibernate 利用数据库以及配置数据来为应用程序提供持续性服务(以及持续性对象). 下面是一个非常高水平的 Hiber ...
- android 事件拦截 (Viewpager不可以左右滑动)
以前没有做过真正的需求,所以从来没有觉得事件拦截分发处理有什么好懂的. 现在做需求了,真的是什么需求都有,你作为开发都要去研究实现.比如说,只能点不能滑动的viewpager.其实这都可以不用view ...