BZOJ 3531 [Sdoi2014]旅行 树链剖分 线段树
来源:互联网 发布:mysql 名称去重复连接 编辑:程序博客网 时间:2024/05/21 11:16
Description
S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教, S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
Input
输入的第一行包含整数N,Q依次表示城市数和事件数。
接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
接下来N-1行每行两个整数x,y表示一条双向道路。
接下来Q行,每行一个操作,格式如上所述。
Output
对每个QS和QM事件,输出一行,表示旅行者记下的数字。
Sample Input
5 6
3 1
2 3
1 2
3 3
5 1
1 2
1 3
3 4
3 5
QS 1 5
CC 3 1
QS 1 5
CW 3 3
QS 1 5
QM 2 4
Sample Output
8
9
11
3
HINT
N,Q < =10^5,C < =10^5
数据保证对所有QS和QM事件,起点和终点城市的信仰相同;在任意时
刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。
对于每一个宗教建一棵线段树,动态开点即可,可以说是非常巧妙,非常厉害233,每次去询问一个宗教即可,链上询问这颗这个宗教的线段树
说得好轻巧好容易一样(虽然的确很简单),但是我RE了一下午,就因为有个for register int i=head[u],我写的是for register int i=1,真的是一下午没有看出来
#include<iostream>#include<cstdio>#include<cstring>#define M 10000005using namespace std;const int MAXN = 100000 + 10;int n, m, cnt, size;int w[100005], c[MAXN], root[MAXN];int son[MAXN], fa[MAXN], dp[MAXN], sz[MAXN], top[MAXN], dfn[MAXN], tid[MAXN], head[MAXN], timer, tail;struct Tree{ int lson, rson, sum, maxn; }tree[ 10000005 + 10 ];struct Line{ int to, nxt; } line[ MAXN * 2 + 10 ];void add_line( int from, int to ){ line[ ++tail ].to = to; line[tail].nxt = head[from]; head[from] = tail; }void dfs1( int u, int fat, int dep ) { sz[u] = 1; fa[u] = fat; dp[u] = dep; for( register int i = head[u]; i ; i = line[i].nxt ) { int v = line[i].to; if( v == fat ) return; dfs1( v, u, dep + 1 ); sz[u] += sz[v]; if( son[u] == -1 || sz[son[u]] < sz[v] ) son[u] = v; }}void dfs2( int u, int tp ) { top[u] = tp; dfn[u] = ++timer; tid[timer] = u; if( son[u] == -1 ) return; dfs2( son[u], tp ); for( register int i = head[u]; i ; i = line[i].nxt ) { int v = line[i].to; if( v == fa[u] || v == son[u] ) continue; dfs2( v, v ); }}int LCA( int x, int y ) { while( top[x] != top[y] ) { if( dp[top[x]] < dp[top[y]] ) swap( x, y ); x = fa[top[x]]; } if( dp[x] < dp[y] ) return x; else return y;}void pushup( int rt ) { tree[rt].maxn = max( tree[tree[rt].lson].maxn, tree[tree[rt].rson].maxn ); tree[rt].sum = tree[tree[rt].lson].sum + tree[tree[rt].rson].sum;}void modify( int &k, int l, int r, int loc, int num ) { if( !k ) k = ++size; if( l == r ) { tree[k].maxn = tree[k].sum = num; return; } int mid = ( l + r ) >> 1; if( loc <= mid ) modify( tree[k].lson, l, mid, loc, num ); else modify( tree[k].rson, mid + 1, r, loc, num ); pushup( k );}int askmax( int k, int l, int r, int x, int y ) { if( !k ) return 0; if( l == x && y == r ) return tree[k].maxn; int mid = ( l + r ) >> 1; if( y <= mid ) return askmax( tree[k].lson, l, mid, x, y ); else if( x > mid )return askmax( tree[k].rson, mid + 1, r, x, y ); else return max( askmax( tree[k].lson, l, mid, x, mid ), askmax( tree[k].rson, mid + 1, r, mid + 1, y ) );}int asksum( int k, int l, int r, int x, int y ) { if( !k ) return 0; if( l == x && y == r ) return tree[k].sum; int mid = ( l + r ) >> 1; if( y <= mid )return asksum( tree[k].lson, l, mid, x, y ); else if( x > mid )return asksum( tree[k].rson, mid + 1, r, x, y ); else return asksum( tree[k].lson, l, mid, x, mid ) + asksum( tree[k].rson, mid + 1, r, mid + 1, y );}int solvemax( int c, int x, int y ) { int maxn = 0; while( top[x] != top[y] ) { maxn = max( maxn, askmax( root[c], 1, n, dfn[top[x]], dfn[x] ) ); x = fa[top[x]]; } maxn = max( maxn, askmax( root[c], 1, n, dfn[y], dfn[x] ) ); return maxn;}int solvesum( int c, int x, int y ) { int sum = 0; while( top[x] != top[y] ) { sum += asksum( root[c], 1, n, dfn[top[x]], dfn[x] ); x = fa[top[x]]; } sum += asksum( root[c], 1, n, dfn[y], dfn[x] ); return sum;}int main( ) { scanf( "%d%d", &n, &m ); memset( son, -1, sizeof(son) ); for( register int i = 1; i <= n; i++ ) scanf( "%d%d", &w[i], &c[i] ); for( register int i = 1; i <= n - 1; i++ ) { int ff, tt; scanf( "%d%d", &ff, &tt ); add_line( ff, tt ); add_line( tt, ff ); } dfs1( 1, 0, 0 ); dfs2( 1, 1 ); for( register int i = 1; i <= n; i++ ) modify( root[c[i]], 1, n, dfn[i], w[i] ); for( register int i = 1; i <= m; i++ ) { char ch[10];int x,y; scanf( "%s%d%d", ch, &x, &y ); if( ch[0] == 'C' ) { if( ch[1] == 'C' ) { modify( root[c[x]], 1, n, dfn[x], 0 ); c[x] = y; modify( root[c[x]], 1, n, dfn[x], w[x] ); } else { modify( root[c[x]], 1, n, dfn[x], y ); w[x] = y; } } else { int fat = LCA( x, y ); if( ch[1] == 'S' ) { int t = solvesum( c[x], x, fat ) + solvesum( c[x], y, fat ); if( c[x] == c[fat] ) t -= w[fat]; printf( "%d\n", t ); } else { printf( "%d\n", max( solvemax( c[x], x, fat ), solvemax( c[x], y, fat ) ) ); } } } return 0;}
- [树链剖分 线段树] BZOJ 3531 [Sdoi2014]旅行
- BZOJ 3531 [SDOI2014]旅行 树链剖分+线段树
- bzoj 3531: [Sdoi2014]旅行 线段树+树链剖分
- BZOJ 3531 [Sdoi2014]旅行 树链剖分 线段树
- BZOJ 3531 SDOI2014 旅行 树链剖分
- bzoj 3531: [Sdoi2014]旅行 树链剖分
- BZOJ 3531 [Sdoi2014]旅行 树链剖分
- BZOJ 3531: [Sdoi2014]旅行
- 【BZOJ 3531】 [Sdoi2014]旅行
- [bzoj 3531]sdoi2014 旅行
- bzoj 3531 [SDOI2014]旅行
- bzoj 3531: [Sdoi2014]旅行
- |BZOJ 3531|树链剖分|动态开点线段树|[Sdoi2014]旅行
- 【bzoj 3531】 [Sdoi2014]旅行(树链剖分+树套树)
- bzoj3531 [Sdoi2014]旅行 树链剖分 线段树
- BZOJ 3531 SDOI2014 旅行(travel) 树链剖分模板题
- bzoj3531 [Sdoi2014]旅行 【树链剖分+线段树动态开点】
- 【BZOJ】【P3531】【SDOI2014】【旅行】【题解】【树链剖分】
- Java学习笔记(23)--foreach 使用
- Android瀑布流照片墙实现,体验不规则排列的美感
- 安卓文件下载之断点续传(一)
- 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛:Overlapping Rectangles
- Linux创建,删除用户,修改用户组
- BZOJ 3531 [Sdoi2014]旅行 树链剖分 线段树
- maven配置阿里云镜像
- Android多点触控技术实战,自由地对图片进行缩放和移动
- 持久层框架的关注点
- 快速生成mif文件
- 数据结构(三)--循环队列
- 0925 视图、游标、包、触发器、索引
- 软件工程 习题二 课后作业
- 做机器鱼二次开发遇到的问题