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 解题报告的更多相关文章

  1. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  2. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  3. 洛谷 P3802 小魔女帕琪 解题报告

    P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...

  4. 洛谷 P2606 [ZJOI2010]排列计数 解题报告

    P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...

  5. 洛谷1303 A*B Problem 解题报告

    洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...

  6. 【刷题】洛谷 P3573 [POI2014]RAJ-Rally

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

  7. 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告

    [USACO13OPEN]照片Photo 题目描述 农夫约翰决定给站在一条线上的\(N(1 \le N \le 200,000)\)头奶牛制作一张全家福照片,\(N\)头奶牛编号\(1\)到\(N\) ...

  8. 洛谷 P1379 八数码难题 解题报告

    P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...

  9. NOIP2015 D2T3 洛谷2680 BZOJ4326 运输计划 解题报告

    前言:个人认为这是历年NOIP中比较简单的最后一题了,因此将自己的思路与大家分享. 题目大意: 给一棵无根树,给出m条路径.允许将树上的一条边的权值改为0.求m条路径长度最大值的最小值.n,m< ...

随机推荐

  1. SpringMVC-实现PUT请求上传文件(转)

    因为在图片上传的时候使用的是二进制的方式上传,所以使用隐藏域进行方法转换方式失效,转方法: https://www.cnblogs.com/morethink/p/6378015.html 可是后来我 ...

  2. egg- 配置

    1. model module.exports = app => { const { INTEGER, STRING, TEXT } = app.Sequelize; const User = ...

  3. js点击获取标签里面id属性

    <html xmlns="http://www.w3.org/1999/xhtml"> <head > <title></title> ...

  4. 交换机基础配置之结合以太通道的vlan设置

    我们将以上面的拓扑图来做实验,建立以太通道,并设置好vlan,将pc1和pc3放在同一vlan,将pc2和pc4放在同一vlan,同一vlan能跨交换机通信 在一切还没布置之前,四台pc机都在同一网段 ...

  5. Shell学习——数值运算

    在Bash shell中,可以利用let.(( )).[]执行基本的算术操作,在高级操作时,使用expr和bc两个工具1.let[root@client02 ~]# no1=4[root@client ...

  6. 11.VUE学习之提交表单时拿到input里的值

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  7. php图片上传旋转压缩方法

    用到php的exif扩展,需要开启exif 在php.ini文件中去掉exif组件的注释 extension=php_mbstring.dll //要放在php_exif.dll前面让它先加载 ext ...

  8. win8电脑字体出现方格的解决方法

    一般电脑出现乱码有几种可能,最常见的可能就是电脑字体的丢失,其次就是电脑字体被病毒所损坏,因此,首先我们要做的就是下载字体并进行安装. 下载 simsun.tcc点击安装,如果电脑字体依然是这种情况( ...

  9. python——直方图均衡化

    from PIL import Image from pylab import * from numpy import * def histeq(im,nbr_bins = 256): "& ...

  10. Android面试收集录9 IntentService详解

    一. 定义 IntentService是Android里面的一个封装类,继承自四大组件之一的Service. 二.作用 处理异步请求,实现多线程 三. 工作流程 注意:若启动IntentService ...