bzoj 3832: [Poi2014]Rally(线段树+拓扑排序)

3832: [Poi2014]Rally

Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge

Submit: 113  Solved: 56

[Submit][Status][Discuss]

Description

An annual bicycle rally will soon begin in Byteburg. The bikers of Byteburg are natural long distance cyclists. Local representatives of motorcyclists, long feuding the cyclists, have decided to sabotage
the event.

There are   intersections in Byteburg, connected with one way streets. Strangely enough, there are no cycles in the street network - if one can ride from intersection U to intersection V , then it
is definitely impossible to get from V to U.

The rally‘s route will lead through Byteburg‘s streets. The motorcyclists plan to ride their blazing machines in the early morning of the rally day to one intersection and completely block it. The
cyclists‘ association will then of course determine an alternative route but it could happen that this new route will be relatively short, and the cyclists will thus be unable to exhibit their remarkable endurance. Clearly, this is the motorcyclists‘ plan
- they intend to block such an intersection that the longest route that does not pass through it is as short as possible.

给定一个N个点M条边的有向无环图,每条边长度都是1。

请找到一个点,使得删掉这个点后剩余的图中的最长路径最短。

Input

In the first line of the standard input, there are two integers, N and M(2<=N<=500 000,1<=M<=1 000 000), separated by a single space, that specify the number of intersections and streets in Byteburg.
The intersections are numbered from   to  . The   lines that follow describe the street network: in the  -th of these lines, there are two integers, Ai, Bi(1<=Ai,Bi<=N,Ai<>Bi), separated by a single space, that signify that there is a one way street from the
intersection no. Ai to the one no. Bi.

第一行包含两个正整数N,M(2<=N<=500 000,1<=M<=1 000 000),表示点数、边数。

接下来M行每行包含两个正整数A[i],B[i](1<=A[i],B[i]<=N,A[i]<>B[i]),表示A[i]到B[i]有一条边。

Output

The first and only line of the standard output should contain two integers separated by a single space. The first of these should be the number of the intersection that the motorcyclists should block,
and the second - the maximum number of streets that the cyclists can then ride along in their rally. If there are many solutions, your program can choose one of them arbitrarily.

包含一行两个整数x,y,用一个空格隔开,x为要删去的点,y为删除x后图中的最长路径的长度,如果有多组解请输出任意一组。

Sample Input

6 5

1 3

1 4

3 6

3 4

4 5

Sample Output

1 2

HINT

Source

鸣谢Claris提供SPJ及译文

[Submit][Status][Discuss]


题解: 线段树+拓扑排序

非常神奇的一个思路。

f[i] 表示从起始点到该点的最长路径

g[i] 表示从该点到终点(无法再走)的最长路径

对于边(u,v) ,那么他能产生的最长路就是f[u]+1+g[v]

于是我们就是可以建立一棵权值线段树,来维护删除某个节点后的最长路。

刚开始的时候先把所有点的g[i]加入线段树,然后按照拓扑序一次删除每个节点。

在删除节点的时候要把所有用他的入边更新的答案删去,再把g[i]从这个点开始的最长路删去,为什么只用删去这一条路呢?因为我们刚开始加入的时候就只加入了这个点之后的最长路。然后这时线段树中的最大值就是删去该点后的答案。那么有人会有疑问?一条最长路上的每条边能产生的最长路的值都是相同的那么只删除这个点的,会不会在这条路径上的其他边的最大值会影响答案呢?其实是不会的,因为我们是按照拓扑序来搞的,他后面的点只加入了g[x],根本没有加入这条路径的信系。

然后再把这个点的出边所能产生的最长路加入线段树,并把f[i]加入线段树,因为如果之后再用该点更新答案的话,一定会选择到该点的最长路,其他的路径就没有用了。之所以要把所有出边产生的最长路加入线段树,是因为在删除这个点之后的点的时候,可能会把这个点以后最长路破坏,所有需要把所有路径记录下来,保证可以通过所有可能的路径更新答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000003
using namespace std;
int n,m;
int next[N],point[N],v[N],f[N],ins[N],q[N],tot;
int next1[N],point1[N],v1[N],g[N],outs[N],p[N],tot1;
int cnt[N*4],maxn[N*4];
void add(int x,int y)
{
	tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void add1(int x,int y)
{
	tot1++; next1[tot1]=point1[x]; point1[x]=tot1; v1[tot1]=y;
}
void solve()
{
	int tail=0; int head=0;
	for (int i=1;i<=n;i++)
	 if (!ins[i]) q[++tail]=i,f[i]=0;
	while (head<tail)
	{
		int now=q[++head];
		for (int i=point[now];i;i=next[i])
		{
		 if (f[v[i]]<f[now]+1)  f[v[i]]=f[now]+1;
		 if (!--ins[v[i]]) q[++tail]=v[i];
	    }
	}
    tail=0; head=0;
    for (int i=1;i<=n;i++)
     if (!outs[i]) p[++tail]=i,g[i]=0;
    while (head<tail)
    {
    	int now=p[++head];
    	for (int i=point1[now];i;i=next1[i])
    	{
    	 if (g[v1[i]]<g[now]+1)  g[v1[i]]=g[now]+1;
    	 if (!--outs[v1[i]])  p[++tail]=v1[i];
        }
    }
}
void pointchange(int now,int l,int r,int x,int v)
{
	if (l==r)
	 {
	 	cnt[now]+=v;
	 	if (cnt[now]>0)  maxn[now]=l;
	 	else maxn[now]=-1,cnt[now]=0;//这里需要注意不能无限制的减下去,因为有可能这个权值的不止一个,所以会删不止一次,但是我们在加入的时候,一定需要一下就把这个值加上去,而不是先恢复之前减掉的
	 	return;
	 }
	int mid=(l+r)/2;
	if (x<=mid) pointchange(now<<1,l,mid,x,v);
	else pointchange(now<<1|1,mid+1,r,x,v);
	maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	 {
	 	int x,y; scanf("%d%d",&x,&y);
	 	add(x,y);  ins[y]++;
	 	add1(y,x); outs[x]++;
	 }
	solve();
	int ans=1000000000;  int ansx=0;
	for (int i=1;i<=n;i++) pointchange(1,0,n,g[i],1);
    for (int i=1;i<=n;i++)
     {
     	int x=q[i];
     	for (int i=point1[x];i;i=next1[i])
     	 pointchange(1,0,n,g[x]+1+f[v1[i]],-1);
     	pointchange(1,0,n,g[x],-1);
     	if (maxn[1]<ans) ans=maxn[1],ansx=x;
		for (int i=point[x];i;i=next[i])
		 pointchange(1,0,n,f[x]+1+g[v[i]],1);
		pointchange(1,0,n,f[x],1);
     }
    printf("%d %d\n",ansx,ans);
}
时间: 2024-10-07 06:33:58

bzoj 3832: [Poi2014]Rally(线段树+拓扑排序)的相关文章

BZOJ 3832: [Poi2014]Rally

Sol 线段树+拓扑序. 先把图的拓扑序搞出来,然后统计从起点到该点最长链,从该点到终点的最长链,然后建个起点终点,这里跟网络流很像,把它统一到一个有起点的图中,这里也要注意下细节处理.S,T的一个边割掉后最长链就是答案. 然后一开始所有点都在T的集合中,一个个将点加入S集合,用线段树维护每个节点 (从起点到该点最长链+从终点到该点的最长链)的长度,其实就是一个权值线段树,然后就是加加减减的... Code /*******************************************

【刷题】BZOJ 3832 [Poi2014]Rally

Description An annual bicycle rally will soon begin in Byteburg. The bikers of Byteburg are natural long distance cyclists. Local representatives of motorcyclists, long feuding the cyclists, have decided to sabotage the event. There are intersections

HDU5638 / BestCoder Round #74 (div.1) 1003 Toposort 线段树+拓扑排序

Toposort 问题描述 给出nn个点mm条边的有向无环图. 要求删掉恰好kk条边使得字典序最小的拓扑序列尽可能小. 输入描述 输入包含多组数据. 第一行有一个整数TT, 表示测试数据组数. 对于每组数据: 第一行包含3个整数nn, mm和kk (1 \le n \le 100000, 0 \le k \le m \le 200000)(1≤n≤100000,0≤k≤m≤200000), 表示图中结点数目, 图中边的数目以及要删的边数. 接下来mm行, 每行包含两个整数u_iu?i?? and

hdu 5195 DZY Loves Topological Sorting 线段树+拓扑排序

DZY Loves Topological Sorting Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5195 Description A topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for ev

hdu5195 DZY Loves Topological Sorting 线段树+拓扑排序

要求在一个DAG中删去不多于k条边,使得拓扑序的字典序最大. 贪心策略:每次删去入度小于res的,序号尽量大的点的入边. 需要用线段树维护区间最小值. 代码: #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<vector> using name

[CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)

题目描述 你有一个长度为$n$的排列$P$与一个正整数$K$你可以进行如下操作若干次使得排列的字典序尽量小对于两个满足$|i−j|\geqslant K$且$|P_i−P_j|=1$的下标$i$与$j$,交换$P_i$与$P_j$ 输入格式 第一行包括两个正整数$n$与$K$第二行包括$n$个正整数,第$i$个正整数表示$P_i$ 输出格式 输出一个新排列表示答案输出共$n$行,第$i$行表示$P_i$ 样例 样例输入: 8 34 5 7 8 3 1 2 6 样例输出: 12675348 数据范

bzoj 2120: 数颜色 线段树套平衡树

/************************************************************** Problem: 2120 User: wangyucheng Language: C++ Result: Time_Limit_Exceed ****************************************************************/ #include<iostream> #include<cstdio> #incl

Bzoj 2752 高速公路 (期望,线段树)

Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时候把\(r - 1\)就好了. 这里的期望显然就是路径的平均值. 期望值: \[\dfrac{\sum_{i=l}^r\sum_{j=l}^{r}dis[i][j]}{C_{r-l+1}^2}\] 下面部分可以直接算出: 上面这一部分比较难维护. 考虑每一条边会被走过多少次. \[ans = \su

HDU5195 线段树+拓扑

DZY Loves Topological Sorting Problem Description A topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge (u→v) from vertex u to vertex v , u comes before v in the ordering