[bzoj1036][ZJOI2008]树的统计Count 树链剖分

来源:互联网 发布:积分商城数据库设计 编辑:程序博客网 时间:2024/04/26 21:18

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
[Submit][Status][Discuss]

Description

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

  输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

  对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

Sample Output

4
1
2
2
10
6
5
6
5
16

HINT

裸题,终于了解树链剖分了,下次写LCT
#include<iostream>#include<cstring>#include<cstdio>#define INF 0x7fffffffusing namespace std;const int N = 300000 + 5;int n,q,sz,cnt,id,root,dep[N],v[N],last[N],fa[N],pos[N],bel[N],siz[N];int ls[N*4],rs[N*4],sum[N*4],mx[N*4],l[N*4],r[N*4]; char ch[10];struct Edge{ int to,next; }e[N*2];void insert( int u, int v ){e[++cnt].to = v; e[cnt].next = last[u]; last[u] = cnt;e[++cnt].to = u; e[cnt].next = last[v]; last[v] = cnt;}void dfs1( int x ){siz[x] = 1;for( int i = last[x]; i; i = e[i].next ){if( e[i].to == fa[x] ) continue;dep[e[i].to] = dep[x]+1; fa[e[i].to] = x;dfs1(e[i].to); siz[x] += siz[e[i].to];}}void dfs2( int x, int chain ){int k = 0; pos[x] = ++sz; bel[x] = chain;for( int i = last[x]; i; i = e[i].next )if( dep[e[i].to] > dep[x] && siz[e[i].to] > siz[k] )k = e[i].to;if( !k ) return ; dfs2(k,chain);for( int i = last[x]; i; i = e[i].next )if( e[i].to != k && dep[e[i].to] > dep[x] )dfs2(e[i].to,e[i].to);}void build( int &k, int L, int R ){l[++id] = L; r[id] = R; k = id;if( L == R ) return ;int mid = (L+R)>>1;build(ls[k],L,mid); build(rs[k],mid+1,R);}void change( int k, int x, int y ){int mid = (l[k]+r[k])>>1;if( l[k] == r[k] ){ sum[k] = mx[k] = y; return; }if( x <= mid ) change( ls[k], x, y );else change( rs[k], x, y );sum[k] = sum[ls[k]]+sum[rs[k]];mx[k] = max(mx[ls[k]],mx[rs[k]]);}int query_sum( int k, int x, int y ){if( l[k] == x && r[k] == y ) return sum[k];int mid = (l[k]+r[k])>>1;if( y <= mid ) return query_sum( ls[k], x, y );if( x > mid ) return query_sum( rs[k], x, y );return query_sum(ls[k],x,mid)+query_sum(rs[k],mid+1,y);}int query_mx( int k, int x, int y ){if( l[k] == x && r[k] == y ) return mx[k];int mid = (l[k]+r[k])>>1;if( y <= mid ) return query_mx( ls[k], x, y );if( x > mid ) return query_mx( rs[k], x, y );return max(query_mx(ls[k],x,mid),query_mx(rs[k],mid+1,y));}int solve_sum( int x, int y ){int res = 0;while( bel[x] != bel[y] ){if( dep[bel[x]] < dep[bel[y]] ) swap(x,y);res += query_sum(root,pos[bel[x]],pos[x]);x = fa[bel[x]];}if( pos[x] > pos[y] ) swap(x,y);res += query_sum(root,pos[x],pos[y]);return res;}int solve_mx( int x, int y ){int res = -INF;while( bel[x] != bel[y] ){if( dep[bel[x]] < dep[bel[y]] ) swap(x,y);res = max(res,query_mx(root,pos[bel[x]],pos[x]));x = fa[bel[x]];}if( pos[x] > pos[y] ) swap(x,y);res = max(res,query_mx(root,pos[x],pos[y]));return res;}int main(){scanf("%d", &n);for( int i = 1,a,b; i < n; i++ ){scanf("%d%d", &a, &b);insert(a,b);} for( int i = 1; i <= n; i++ ) scanf("%d", &v[i]);dfs1(1); dfs2(1,1); build(root,1,n);for( int i = 1; i <= n; i++ ) change(root,pos[i],v[i]);scanf("%d", &q);for( int i = 1, x, y; i <= q; i++ ){scanf("%s%d%d",ch,&x,&y);if(ch[0]=='C'){ v[x] = y; change(1,pos[x],y); }else{if(ch[1]=='M') printf("%d\n",solve_mx(x,y));else printf("%d\n",solve_sum(x,y));}}return 0;}


阅读全文
0 0
原创粉丝点击