[HNOI2016]网络(树链剖分+线段树+大根堆)

[HNOI2016]网络

problem

solution

另辟蹊径,不把交互请求赋在新增路径上,反而把交互请求赋在树上除去该请求路径覆盖点的其它点上

显然,路径问题树剖是非常可以的、
在这里插入图片描述

那么一个点上的信息就表示所有不经过该点的交互请求,用堆存储下来

但是又有交互请求删除问题,就在点上再来一个堆存储已经删除的请求

查询就相当于单点查询,两个大根堆,如果堆头相同,就删去,直到堆头不同

code

#include <queue>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 200005
pair < int, int > path[maxn];
int n, m, cnt;
vector < int > G[maxn];
int dfn[maxn], dep[maxn], Top[maxn], siz[maxn], son[maxn], f[maxn];

struct node {
	int u, v, w;
	node(){}
	node( int U, int V, int W ) {
		u = U, v = V, w = W;
	}
}opt[maxn];

class New_Queue {
	private :
		priority_queue < int > Delete, Vis;
	public :
		int find() {
			while( ! Delete.empty() && ! Vis.empty() ) {
				if( Delete.top() == Vis.top() )
					Delete.pop(), Vis.pop();
				else
					break;
			}
			return Vis.empty() ? -1 : Vis.top();
		}
		void insert( int x ) {
			Vis.push( x );
		}
		void erase( int x ) {
			Delete.push( x );
		}
};

class SegMentTree {
	private :
		New_Queue t[maxn << 2];
	public :
		void modify( int num, int l, int r, int L, int R, int w, int opt ) {
			if( r < L || R < l ) return;
			if( L <= l && r <= R ) {
				opt ? t[num].insert( w ) : t[num].erase( w );
				return;
			}
			int mid = ( l + r ) >> 1;
			modify( num << 1, l, mid, L, R, w, opt );
			modify( num << 1 | 1, mid + 1, r, L, R, w, opt );
		}
		int query( int num, int l, int r, int pos ) {
			if( l == r ) return t[num].find();
			int mid = ( l + r ) >> 1;
			if( pos <= mid )
				return max( t[num].find(), query( num << 1, l, mid, pos ) );
			else
				return max( t[num].find(), query( num << 1 | 1, mid + 1, r, pos ) );
		}
}MS;

void dfs1( int u, int fa ) {
	f[u] = fa, dep[u] = dep[fa] + 1, siz[u] = 1;
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i];
		if( v == fa ) continue;
		else dfs1( v, u );
		siz[u] += siz[v];
		if( ! son[u] || siz[v] > siz[son[u]] )
			son[u] = v;
	}
}

void dfs2( int u, int t ) {
	dfn[u] = ++ cnt, Top[u] = t;
	if( ! son[u] ) return;
	else dfs2( son[u], t );
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i];
		if( v == f[u] || v == son[u] ) continue;
		else dfs2( v, v );
	}
}

void modify( int u, int v, int w, int opt ) {
	cnt = 0;
	while( Top[u] ^ Top[v] ) {
		if( dep[Top[u]] < dep[Top[v]] ) swap( u, v );
		path[++ cnt] = make_pair( dfn[Top[u]], dfn[u] );
		u = f[Top[u]];
	}
	if( dep[u] < dep[v] ) swap( u, v );
	path[++ cnt] = make_pair( dfn[v], dfn[u] );
	sort( path + 1, path + cnt + 1 );
	for( int i = 1, k = 0;i <= cnt;k = path[i ++].second )
		if( k + 1 != path[i].first )
			MS.modify( 1, 1, n, k + 1, path[i].first - 1, w, opt );
	if( path[cnt].second ^ n )
		MS.modify( 1, 1, n, path[cnt].second + 1, n, w, opt );
}

int main() {
	scanf( "%d %d", &n, &m );
	for( int i = 1, u, v;i < n;i ++ ) {
		scanf( "%d %d", &u, &v );
		G[u].push_back( v );
		G[v].push_back( u );
	}
	dfs1( 1, 0 ), dfs2( 1, 1 );
	for( int i = 1, type, a, b, v;i <= m;i ++ ) {
		scanf( "%d %d", &type, &a );
		switch( type ) {
			case 0 : {
				scanf( "%d %d", &b, &v );
				opt[i] = node( a, b, v );
				modify( a, b, v, 1 );
				break;
			}
			case 1 : {
				modify( opt[a].u, opt[a].v, opt[a].w, 0 );
				break;
			}
			case 2 : {
				printf( "%d\n", MS.query( 1, 1, n, dfn[a] ) );
				break;
			}
		}
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值