题目

点这里看题目。

分析

面对这种题还没有什么经验……

Subtask 1

暴力删暴力判,复杂度为 \(O((n+m)q)\)

Subtask 2

尝试优化一下暴力。

尝试将 \(O((n+m)q)\) 变成 \(O((n+m)m)\)。之所以会判 \(q\) 次,主要在于纯暴力会对已经确定为 0 的边重复判断。然而,如果一条边已经删不了了,在此之后又不会新增边,所以如果之后又遇到它,肯定还是删不了。所以每条边只需要检查 1 次即可判定状态。

Subtask 3

好奇怪,为什么我妹想到?

我们没有必要在线处理问题,因为这必然意味着在线处理连通性,是我们暂时无法完成的。

先把所有重复的 \(x\) 处理掉:对于同一 \(x\),只有第一次出现的位置有判断价值,其后必然全为 0。之后我们可以二分找出没有被删的那条边

Remark.

主要还是自己完全是在线的思路,根本没有意识到可以离线解决。

从离线的角度来看,这其实就是将时间排扁成一维信息的常规思路。

当然,用二分进行查找的方法也应该熟悉。

Subtask 4

类似于 Subtask 3,当我们找出第一条之后,我们也可以找出第二条、第三条……

正解

将上面的思路拓展,我们干的事情是就是反复使用二分找出所有的 0 边,不妨设这些边为 \(e_1,e_2,\dots,e_k\)

但再深入思考一下:当我们找到 \(e_1\),由于更早的边都已被删除,之后有效的路径必然满足每一条边的删除时间都不早于 \(e_1\) 的时间。类似地,找到 \(e_2\) 时,限制就变成了路径上最早被删除的边的删除时间不早于 \(e_1\) 的时间,次早被删除的边的删除时间不早于 \(e_2\) 的时间,依此类推。

根据 \(e_1,e_2,\dots,e_k\) 的性质,我们可以推知最终剩下来的路径,都必须最小化路径上边的删除时间从小到大排序后的字典序。字典序可以对应,所以可以赋权并尝试和最短路模型联系起来,如果一条边从未被删除,则其权为 \(0\)(可以认为是 \(2^{-\infty}\));否则,若在第 \(t\) 次操作中第一次被删除,则其权为 \(2^{q-t}\)

Remark.

文字描述显得比较抽象。实际上想像动态删边的过程就可以很好地理解这个过程了。

另外值得提醒的——综合考虑已有条件

暴力计算最短路复杂度为 \(O(m^2\log m)\),瓶颈在于比较最短路的长度。既然无法直接用“权”比较,我们就只能考虑路径本身了。当我们把所有路径拉出来的时候,我们知道会有一棵最短路树,并且最短路树可以反映路径之间的公共部分和非公共部分。路径权值的差别必然出现在非公共部分,而最短路是到根的路径,所以比较 \(u,v\) 的最短路长度时,我们可以直接比较非公共树链。更进一步地,由于\(0\) 边权互不相同,所以我们比较最高位——也就是指数的 \(\max\)——即可判断大小关系。

Dijkstra 过程中树会动态扩增,所以需要用倍增维护,复杂度为 \(O(m\log n\log m)\)

代码

#include <cmath>
#include <cstdio>

#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )

const int INF = 1e9;
const int MAXN = 2e5 + 5, MAXLOG = 18;

template<typename _T>
inline void Read( _T &x ) {
	x = 0; char s = getchar(); bool f = false;
	while( s < '0' || '9' < s ) { f = s == '-', s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
	if( f ) x = -x;
}

template<typename _T>
inline void Write( _T x ) {
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) Write( x / 10 );
	putchar( x % 10 + '0' );
}

template<typename _T>
inline _T Min( const _T &a, const _T &b ) {
	return a < b ? a : b;
}

template<typename _T>
inline _T Max( const _T &a, const _T &b ) {
	return a > b ? a : b;
}

struct Edge {
	int to, nxt, w;
} Graph[MAXN << 1];

int tre[MAXN << 2], bas;

int mx[MAXLOG][MAXN], fath[MAXLOG][MAXN];
int dep[MAXN], pre[MAXN];
bool vis[MAXN], imp[MAXN];

int head[MAXN], cnt = 0;
int fr[MAXN], to[MAXN], tim[MAXN];

int rmvId[MAXN];

int N, M, Q, lg2;

inline void AddEdge( const int &from, const int &to, const int &W ) {
	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
	Graph[cnt].w = W, head[from] = cnt;
}

inline void Build( const int &n ) {
	for( bas = 1 ; bas < n ; bas <<= 1 );
	rep( i, 1, bas ) tre[i + bas - 1] = i == 1 ? 1 : N + 1;
	per( i, bas - 1, 1 ) tre[i] = tre[i << 1];
}

inline void Balance( int &u, const int &stp, int &ret ) {
	for( int i = 0 ; ( 1 << i ) <= stp ; i ++ )
		if( stp >> i & 1 ) ret = Max( ret, mx[i][u] ), u = fath[i][u];
}

inline bool Cmp( int x, int y, const int &v1Init = - INF, const int &v2Init = - INF ) {
	if( x > N ) return false;
	if( y > N ) return true;
	int v1 = v1Init, v2 = v2Init;
	if( dep[x] > dep[y] ) Balance( x, dep[x] - dep[y], v1 );
	if( dep[x] < dep[y] ) Balance( y, dep[y] - dep[x], v2 );
	if( x == y ) return v1 <= v2;
	per( i, lg2, 0 ) if( fath[i][x] ^ fath[i][y] ) {
		v1 = Max( mx[i][x], v1 ), x = fath[i][x];
		v2 = Max( mx[i][y], v2 ), y = fath[i][y];
	}
	return Max( v1, mx[0][x] ) <= Max( v2, mx[0][y] );
}

inline void Upt( const int &x ) {
	static int y, z; y = tre[x << 1], z = tre[x << 1 | 1];
	tre[x] = Cmp( fath[0][y], fath[0][z], mx[0][y], mx[0][z] ) ? y : z;
}

inline void Update( int x ) {
	tre[x + bas - 1] = x;
	for( x += bas - 1 ; x >>= 1 ; Upt( x ) );
}

inline void Erase( int x ) {
	tre[x + bas - 1] = N + 1;
	for( x += bas - 1 ; x >>= 1 ; Upt( x ) );
}

void Dijkstra() {
	Build( N ), dep[1] = 0;
	rep( i, 1, N + 1 ) mx[0][i] = - INF, fath[0][i] = N + 1;
	while( tre[1] <= N ) {
		int u = tre[1]; 
		Erase( u ), vis[u] = true;
		
		dep[u] = dep[fath[0][u]] + 1;
		rep( j, 1, lg2 ) {
			fath[j][u] = fath[j - 1][fath[j - 1][u]];
			mx[j][u] = Max( mx[j - 1][fath[j - 1][u]], mx[j - 1][u] );
		}
		for( int i = head[u], v ; i ; i = Graph[i].nxt )
			if( ! vis[v = Graph[i].to] && Cmp( u, fath[0][v], Graph[i].w, mx[0][v] ) )
				mx[0][v] = Graph[i].w, fath[0][v] = u, pre[v] = i, Update( v );
	}
}

int main () {
	Read( N ), Read( M ), Read( Q ), lg2 = log2( N );
	rep( i, 1, M ) Read( fr[i] ), Read( to[i] ), tim[i] = - INF;
	rep( i, 1, Q ) Read( rmvId[i] ), tim[rmvId[i]] = Max( tim[rmvId[i]], Q - i );
	rep( i, 1, M ) AddEdge( fr[i], to[i], tim[i] );
	Dijkstra();
	for( int u = N ; u ^ 1 ; u = fath[0][u] ) imp[pre[u]] = true;
	rep( i, 1, Q ) puts( imp[rmvId[i]] || Q - tim[rmvId[i]] < i ? "0" : "1" );
	return 0;
}

原文地址:http://www.cnblogs.com/crashed/p/16909979.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性