poj 3237 Tree树剖边权更新模板

7 篇文章 0 订阅

题意:将树上某条路径的值正负倒换,或者使某条边变成val,或者查询某条路径上的最大的边权

裸边权更新,与点权更新不同的是,边权中记录边的编号是pos[x] + 1,也就是由重建链之后的子节点记录,pos[x]+1同pos[ son[x] ]。

详见代码,另附有数据

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define pi acos(-1.0)
#define eps 1e-8
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 10010;

struct node{
	int v, nxt;
}e[N << 2];

struct pp{
	int x, y, z;
	pp(){}
	pp( int x, int y, int z ): x(x), y(y), z(z){}
}p[N];

int tot, cnt, n;
int head[N];
int pos[N];
int dep[N];
int top[N];
int val[N];
int son[N];
int pre[N];
int sz[N];

void init()
{
	sz[0] = dep[1] = 0;
	memset( head, -1, sizeof( head ) );
	cnt = tot = 0;
}

void add( int u, int v )
{
	e[cnt].v = v;
	e[cnt].nxt = head[u];
	head[u] = cnt++;

	e[cnt].v = u;
	e[cnt].nxt = head[v];
	head[v] = cnt++;
}

void dfs( int u )
{
	sz[u] = 1;
	son[u] = 0;
	for( int i = head[u]; ~i; i = e[i].nxt )
	{
		int v = e[i].v;
		if( v == pre[u] )
			continue;
		dep[v] = dep[u] + 1;
		pre[v] = u;
		dfs( v );
		sz[u] += sz[v];
		if( sz[v] > sz[ son[u] ] )
			son[u] = v;
	}
}

void rebuild( int u, int anc )
{
	pos[u] = ++tot;
	top[u] = anc;
	if( son[u] )
		rebuild( son[u], anc );
	for( int i = head[u]; ~i; i = e[i].nxt )
	{
		int v = e[i].v;
		if( v != pre[u] && v != son[u] )
			rebuild( v, v );
	}
}

struct seg{
	int l, r;
	int mx, mn;
	int add;
}tr[N << 2];

void pushup( int rt )
{
	tr[rt].mx = max( tr[rt<<1].mx, tr[rt<<1|1].mx );
	tr[rt].mn = min( tr[rt<<1].mn, tr[rt<<1|1].mn );
}

void f( int rt )
{
	tr[rt].add ^= 1;
	int minn = tr[rt].mn, maxx = tr[rt].mx;
	tr[rt].mx = -minn;
	tr[rt].mn = -maxx;
}

void down( int rt )
{
	if( tr[rt].add )
	{
		//tr[rt<<1].add = tr[rt<<1|1].add = tr[rt].add;
		f( rt << 1 );
		f( rt << 1 | 1 );
		tr[rt].add = 0;
	}
}

void build( int l, int r, int rt )
{
	tr[rt].l = l;
	tr[rt].r = r;
	tr[rt].add = 0;
	if( l == r )
	{
		tr[rt].mx = tr[rt].mn = val[l];
		return;
	}
	int mid = (l + r) >> 1;
	build( lson );
	build( rson );
	pushup( rt );
}

void update_point( int pos, int v, int rt )
{
	if( tr[rt].l == tr[rt].r && tr[rt].l == pos )
	{
		tr[rt].mn = tr[rt].mx = v;
		return;
	}
	down(rt);
	int mid = ( tr[rt].l + tr[rt].r ) >> 1;
	if( pos <= mid )
		update_point( pos, v, rt << 1 );
	else
		update_point( pos, v, rt << 1 | 1 );
	pushup( rt );
}

void update( int l, int r, int rt )
{
	if( l <= tr[rt].l && tr[rt].r <= r )
	{
		f( rt );
		return;
	}
	down( rt );
	int mid = ( tr[rt].l + tr[rt].r ) >> 1;
	if( r <= mid )
		update( l, r, rt << 1 );
	else if( l > mid )
		update( l, r, rt << 1 | 1 );
	else
	{
		update( lson );
		update( rson );
	}
	pushup( rt );
}

int query( int l, int r, int rt )
{
	if( l <= tr[rt].l && tr[rt].r <= r )
	{
		return tr[rt].mx;
	}
	down( rt );
	int mid = ( tr[rt].l + tr[rt].r ) >> 1;
	if( r <= mid )
		return query( l, r, rt << 1 );
	else if( l > mid )
		return query( l, r, rt << 1 | 1 );
	else
		return max( query( lson ), query( rson ) );
}

void update1( int x, int y )
{
	while( top[x] != top[y] )
	{
		int f1 = top[x], f2 = top[y];
		if( dep[f1] > dep[f2] )
		{
			update( pos[f1], pos[x], 1 );
			x = pre[f1];
		}
		else
		{
			update( pos[f2], pos[y], 1 );
			y = pre[f2];
		}
	}
	if( x == y )
		return;
	if( dep[x] > dep[y] )
		swap( x, y );
	update( pos[x]+1, pos[y], 1 );
}

int query1( int x, int y )
{
	int res = -inf;
	while( top[x] != top[y] )
	{
		int f1 = top[x], f2 = top[y];
		if( dep[f1] > dep[f2] )
		{
			res = max( res, query( pos[f1], pos[x], 1) );
			x = pre[f1];
		}
		else
		{
			res = max( res, query( pos[f2], pos[y], 1) );
			y = pre[f2];
		}
	}
	if( x == y )
		return res;
	if( dep[x] > dep[y] )
		swap( x, y );
	return max( res, query( pos[x]+1, pos[y], 1 ) );
	//pos[x] + 1 是因为比如有边1->2 = 3,那么val存这条边的时候,val[2] = 3(这里假设pos[x] = x),
	//所以update的时候点的编号要+1,也就是说pos[x]记录的是x与其父亲的边,即pos[son] = pos[fa] + 1,
	// 故还可写成query(pos[son[x]], pos[y], 1)
	//在while中没+1,是因为从top[x]到x就是一条完整的链(top【x】是根x是最下子节点)
}

int main()
{
	int tt;
	scanf("%d", &tt);
	while( tt-- )
	{
		scanf("%d", &n );
		init();
		int u, v, w;
		for( int i = 1; i < n; ++i )
		{
			scanf("%d%d%d", &u, &v, &w);
			add( u, v );
			p[i] = pp( u, v, w );
		}
		dfs( 1 );
		rebuild( 1, 1 );
		for( int i = 1; i < n; i++ )
		{
			if( dep[p[i].x] < dep[p[i].y] )
				swap( p[i].x, p[i].y );
			val[ pos[p[i].x] ] = p[i].z;
			//printf("old: %d new: %d val: %d\n", p[i].x, pos[p[i].x], val[pos[p[i].x]]);
		}
		build( 2, n, 1 );
		char op[10];
		while( ~scanf("%s", op))
		{
			if( op[0] == 'D' )
				break;
			scanf("%d%d", &u, &v);
			if( op[0] == 'C' )
				update_point( pos[p[u].x], v, 1 );
			else if( op[0] == 'N' )
				update1( u, v );
			else
			{
				int ans = query1(u, v);
				printf("%d\n", ans);
			}
		}
	}
	return 0;
}

/*
3
10
1 2 1
2 3 7
3 4 8
4 5 6
5 6 9
6 7 1
7 8 1
8 9 7
9 10 6
NEGATE 4 7
CHANGE 2 3
QUERY 2 9
CHANGE 2 3
QUERY 6 8
NEGATE 1 8
CHANGE 2 7
QUERY 1 3
NEGATE 1 5
CHANGE 4 7
QUERY 3 5
DONE

6
1 2 1
2 3 2
3 4 4
4 5 100
5 6 -1000
QUERY 1 2
CHANGE 1 3
QUERY 1 2
NEGATE 1 2
QUERY 1 3
QUERY 1 2
CHANGE 1 10
QUERY 1 3
NEGATE 1 2
QUERY 1 3
CHANGE 1 10
CHANGE 2 20
QUERY 1 3
NEGATE 1 2
QUERY 1 3
NEGATE 2 3
QUERY 1 3
CHANGE 1 -100
CHANGE 2 -1000
QUERY 1 4
NEGATE 1 6
QUERY 1 6
DONE


100
1 2 265
2 3 133
3 4 508
4 5 197
5 6 437
6 7 849
7 8 577
8 9 503
9 10 478
10 11 434
11 12 877
12 13 691
13 14 54
14 15 295
15 16 421
16 17 166
17 18 550
18 19 410
19 20 868
20 21 476
21 22 283
22 23 410
23 24 915
24 25 308
25 26 301
26 27 553
27 28 609
28 29 733
29 30 770
30 31 635
31 32 581
32 33 753
33 34 707
34 35 448
35 36 738
36 37 841
37 38 389
38 39 532
39 40 210
40 41 458
41 42 595
42 43 989
43 44 678
44 45 214
45 46 746
46 47 548
47 48 117
48 49 758
49 50 437
50 51 840
51 52 555
52 53 726
53 54 490
54 55 719
55 56 403
56 57 329
57 58 92
58 59 311
59 60 664
60 61 207
61 62 170
62 63 548
63 64 713
64 65 556
65 66 705
66 67 82
67 68 508
68 69 59
69 70 45
70 71 670
71 72 540
72 73 826
73 74 262
74 75 504
75 76 989
76 77 408
77 78 896
78 79 388
79 80 15
80 81 485
81 82 219
82 83 977
83 84 641
84 85 985
85 86 189
86 87 64
87 88 641
88 89 320
89 90 788
90 91 441
91 92 785
92 93 163
93 94 153
94 95 852
95 96 36
96 97 10
97 98 145
98 99 956
99 100 641
QUERY 32 69
NEGATE 1 22
CHANGE 40 53
QUERY 17 38
NEGATE 17 65
CHANGE 49 68
QUERY 44 52
NEGATE 11 53
CHANGE 9 68
QUERY 2 49
NEGATE 25 45
CHANGE 23 67
QUERY 89 90
NEGATE 5 37
CHANGE 27 53
QUERY 22 86
NEGATE 6 7
CHANGE 17 23
QUERY 78 93
NEGATE 30 63
CHANGE 56 99
QUERY 3 29
NEGATE 24 38
CHANGE 9 95
QUERY 63 66
NEGATE 69 92
CHANGE 9 91
QUERY 7 27
NEGATE 32 60
CHANGE 48 77
QUERY 47 94
NEGATE 14 27
CHANGE 50 99
QUERY 38 97
NEGATE 11 67
CHANGE 74 83
QUERY 28 81
NEGATE 13 53
CHANGE 55 88
QUERY 2 66
NEGATE 71 95
CHANGE 32 74
QUERY 14 50
NEGATE 1 28
CHANGE 16 80
QUERY 36 75
NEGATE 20 49
CHANGE 22 54
QUERY 5 46
NEGATE 12 37
CHANGE 61 94
QUERY 18 92
NEGATE 19 26
CHANGE 6 94
QUERY 33 60
NEGATE 79 87
CHANGE 30 75
QUERY 55 94
NEGATE 28 79
CHANGE 23 31
QUERY 91 95
NEGATE 28 76
CHANGE 8 41
QUERY 6 25
NEGATE 19 70
CHANGE 17 54
QUERY 52 66
NEGATE 4 95
CHANGE 19 52
QUERY 73 87
DONE

ans:
8
1
7
8


1
3
2
-3
10
2
20
20
-10
4
1000


989
915
68
989
788
989
985
868
705
868
840
852
989
877
746
826
989
989
989
989
785
868
705
985

*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值