[树套树] 网络管理

A:[CTSC2008]网络管理

此题本来是平衡树板块的,但俺写的是树套树,平衡树会多个log
题目

查询第 k k k大,天然主席树可以维护

就不用了平衡树二分,多个 l o g log log

将树上 ( u , v ) (u,v) (u,v)的路径转化为 u u u到根 + + + v v v到根 − - l c a lca lca到根 − - l c a lca lca父亲到根 四个部分

主席树维护每个点到根的所有路由器

每次修改单个路由器 则会影响该路由器的整个子树

整个子树问题转化为树上的 d f n dfn dfn

变成连续的一段区间

用树状数组维护四个部分的前缀和

所以这道题就是树状数组套主席树

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 80005
#define MAX 1e8
vector < int > G[maxn];
int n, Q, num;
int ti[maxn], dep[maxn], Start[maxn], End[maxn];
int sum[maxn * 300], lson[maxn * 300], rson[maxn * 300], root[maxn];//log^2±¶ 
int f[maxn][20];

int lowbit( int x ) {
    
    
	return x & ( -x );
}

struct node {
    
    
	int cnt, t[maxn];
	
	int calc() {
    
    
		int tot = 0;
		for( int i = 1;i <= cnt;i ++ ) tot += sum[rson[t[i]]];
		return tot;
	}
	
	void init( int x ) {
    
    
		cnt = 0;
		while( x ) t[++ cnt] = root[x], x -= lowbit( x );
	}
	
	void choose_l() {
    
    
		for( int i = 1;i <= cnt;i ++ ) t[i] = lson[t[i]];
	}
	
	void choose_r() {
    
    
		for( int i = 1;i <= cnt;i ++ ) t[i] = rson[t[i]];
	}
	
}t1, t2, t3, t4;

void dfs( int u, int fa ) {
    
    
	dep[u] = dep[fa] + 1, f[u][0] = fa, Start[u] = ++ num;
	for( int i = 1;i < 18;i ++ )
		f[u][i] = f[f[u][i - 1]][i - 1];
	for( int i = 0;i < G[u].size();i ++ ) {
    
    
		int v = G[u][i];
		if( v == fa ) continue;
		else dfs( v, u );
	}
	End[u] = num;
}

int LCA( int u, int v ) {
    
    
	if( dep[u] < dep[v] ) swap( u, v );
	for( int i = 17;~ i;i -- )
		if( dep[f[u][i]] >= dep[v] )
			u = f[u][i];
	if( u == v ) return u;
	for( int i = 17;~ i;i -- )
		if( f[u][i] != f[v][i] )
			u = f[u][i], v = f[v][i];
	return f[u][0];
}

void modify( int &x, int l, int r, int pos, int v ) {
    
    
	if( ! x ) x = ++ num;
	sum[x] += v;
	if( l == r ) return;
	int mid = ( l + r ) >> 1;
	if( pos <= mid ) modify( lson[x], l, mid, pos, v );
	else modify( rson[x], mid + 1, r, pos, v );
}

void modify( int x, int pos, int c ) {
    
    
	while( x <= n ) {
    
    
		modify( root[x], 1, MAX, pos, c );
		x += lowbit( x );
	}
}

int query( int l, int r, int k ) {
    
    
	if( l == r ) return l;
	int mid = ( l + r ) >> 1;
	int tot = t1.calc() + t2.calc() - t3.calc() - t4.calc();
	if( tot >= k ) {
    
     
		t1.choose_r(), t2.choose_r(), t3.choose_r(), t4.choose_r();
		return query( mid + 1, r, k );
	}
	else {
    
    
		t1.choose_l(), t2.choose_l(), t3.choose_l(), t4.choose_l();
		return query( l, mid, k - tot );
	}
}

int main() {
    
    
	scanf( "%d %d", &n, &Q );
	for( int i = 1;i <= n;i ++ )
		scanf( "%d", &ti[i] );
	for( int i = 1, u, v;i < n;i ++ ) {
    
    
		scanf( "%d %d", &u, &v );
		G[u].push_back( v );
		G[v].push_back( u );
	}
	dfs( 1, 0 ); num = 0;
	for( int i = 1;i <= n;i ++ )
		modify( Start[i], ti[i], 1 ), modify( End[i] + 1, ti[i], -1 );
	for( int i = 1, k, x, y;i <= Q;i ++ ) {
    
    
		scanf( "%d %d %d", &k, &x, &y );
		if( k ) {
    
    
			int lca = LCA( x, y );
			if( dep[x] + dep[y] - ( dep[lca] << 1 ) + 1 < k ) {
    
    
				printf( "invalid request!\n" );
				continue;
			}
			t1.init( Start[x] ), t2.init( Start[y] ), t3.init( Start[lca] ), t4.init( Start[f[lca][0]] );
			printf( "%d\n", query( 1, MAX, k ) );
		}
		else {
    
    
			modify( Start[x], ti[x], -1 ), modify( End[x] + 1, ti[x], 1 );
			ti[x] = y;
			modify( Start[x], ti[x], 1 ), modify( End[x] + 1, ti[x], -1 );
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Emm_Titan/article/details/114952215
今日推荐