BZOJ 1036: [ZJOI2008]树的统计Count 【树链剖分】

Description

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. 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

Source

树的分治

思路:唔说是树分治,其实裸的树链剖分,这里总结一下树链剖分吧,基本思路就是把树上的路径分成两种,一般是轻重链剖分,然后重链在线段树上查,轻链直接向父亲条的做法,当然由于它们同时存在于线段树中,所以两步是可以合并的,树剖的思想大概就是这样,用到的数组也就是father[]记录父亲,top[]记录重链顶部的节点,id[]记录每个节点在线段树中的位置三个而已,至于其它像size,son之类的只是为了求出前面三个数组所开的辅助数组,一般的话第一个dfs找重儿子,重边,第二个dfs将前面找到的重边连起来变成重链求出top

  1 #include<iostream>
  2 #include<cstdio>
  3 #define maxn 60000
  4 using namespace std;
  5 int w[maxn],head[maxn],point[maxn],next[maxn*2],top[maxn],id[maxn],size_k[maxn],pos=0,now;
  6 int father[maxn],son[maxn],deep[maxn];
  7 struct T
  8 {
  9     int max_x;int sum_x;
 11     T(){max_x=-0x3f3f3f3f;sum_x=0;}
 12 }tree[maxn*4];
 13 T work(T x,T y)
 14 {
 15     T ans;
 16     ans.max_x=max(x.max_x,y.max_x);
 17     ans.sum_x=x.sum_x+y.sum_x;
 18     return ans;
 19 }
 20 T query(int node,int l,int r,int ql,int qr)
 21 {
 22     if(ql<=l && r<=qr)return tree[node];
 23     int mid=(l+r)>>1;T ans;
 24     if(ql<mid)ans=query(node*2,l,mid,ql,qr);
 25     if(mid<qr)ans=work(ans,query(node*2+1,mid,r,ql,qr));
 26     return ans;
 27 }
 28 void update(int node,int l,int r,int p,int x){
 29     if(l+1==r){
 30         tree[node].max_x=x;tree[node].sum_x=x;return ;
 31     }
 32     int mid=(l+r)>>1;
 33     if(p<mid)update(node*2,l,mid,p,x);
 34     else update(node*2+1,mid,r,p,x);
 35     tree[node]=work(tree[node*2],tree[node*2+1]);
 36     return ;
 37 }
 38 void add(int x,int y){
 39     next[++now]=head[x];head[x]=now;point[now]=y;
 40 }
 41 void dfs(int k,int fa)
 42 {
 43     deep[k]=deep[fa]+1;
 44     father[k]=fa;size_k[k]=1;
 46     int max_x=-1;son[k]=-1;
 48     for(int i=head[k];i;i=next[i])
 49     {
 50         if(point[i]==fa)continue;
 51         dfs(point[i],k);
 52         size_k[k]+=size_k[point[i]];
 53         if(size_k[point[i]]>max_x)
 54         {
 55             max_x=size_k[point[i]];
 56             son[k]=point[i];
 57         }
 58     }
 59 }
 60 void dfs2(int k,int fa,int pa)
 61 {
 62     id[k]=++pos;top[k]=pa;
 64     if(son[k]!=-1)dfs2(son[k],k,pa);
 65     for(int i=head[k];i;i=next[i])if(point[i]!=fa && point[i]!=son[k])dfs2(point[i],k,point[i]); 69 }
 70 T find(int x,int y)
 71 {
 72         int fx=top[x],fy=top[y];
 73         T tmp;
 74         while(fx!=fy)
 75         {
 76                 if(deep[fx]<deep[fy])swap(fx,fy),swap(x,y);
 77                 tmp=work(tmp,query(1,1,pos+1,id[fx],id[x]+1));
 78                 x=father[fx];fx=top[x];
 79         }
 80         if(deep[x]<deep[y])swap(x,y);
 81         return work(tmp,query(1,1,pos+1,id[y],id[x]+1));
 82 }
 83 int main()
 84 {
 85         int n,x,y,q;
 86         char ch[100];
 87         scanf("%d",&n);
 88         for(int i=1;i<n;i++)
 89         {
 90                 scanf("%d%d",&x,&y);
 91                 add(x,y);add(y,x);
 93         }
 94         for(int i=1;i<=n;i++)scanf("%d",&w[i]);
 95         scanf("%d",&q);
 96         dfs(1,0);dfs2(1,1,1);
 98         for(int i=1;i<=n;i++)update(1,1,pos+1,id[i],w[i]);102         while(q--)
103         {
104                 scanf("%s%d%d",ch,&x,&y);
105                 if(ch[1]==‘S‘)
106                 {
107                         T u=find(x,y);printf("%d\n",u.sum_x);
109                 }
110                 if(ch[1]==‘M‘)
111                 {
112                         T u=find(x,y);printf("%d\n",u.max_x);
114                 }
115                 if(ch[1]==‘H‘)update(1,1,pos+1,id[x],y);
116         }
117         return 0;
118 }
时间: 2024-10-01 22:45:43

BZOJ 1036: [ZJOI2008]树的统计Count 【树链剖分】的相关文章

HYSBZ - 1036 树的统计Count 树链剖分 求和+最大值

好水0.0 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<string> #define eps 1e-12 #de

BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14982  Solved: 6081[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14302  Solved: 5779[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 18615  Solved: 7598[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)

[ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14968  Solved: 6079[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I II.

BZOJ1036: [ZJOI2008]树的统计Count - 树链剖分 -

1036: [ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n – 1

【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

[BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n

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

[ZJOI2008]树的统计Count 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行,每行

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时... 代码如下: 1 //树链剖分 点权修改 修改单节点 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespa

bzoj 1036 树的统计Count (树链剖分+线段树)

题目大意:给你一棵树,每个点都有点权 有3种操作,修改某节点的权值,求树链上节点的权值的最大值,求树链上节点的权值和 树剖裸题,搜一个树链剖分序,用线段树维护一下即可,总时间 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <queue> 5 #define inf 0x3f3f3f3f 6 #define ll long long 7 #define N