[BZOJ] 1036: [ZJOI2008]树的统计Count
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 18843 Solved: 7689
[Submit][Status][Discuss]
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
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
1
2
2
10
6
5
6
5
16
HINT
Source
Analysis
树链剖分裸题!
在此推荐 ACdreamer的树链剖分原理 !
=w=
树链剖分可以用百度到的一张图解释
那么显然树链剖分还有第三个性质(主要是帮助理解的)
“ 每一个点都在重链上 ”
(其实有点废话,不过我一直对树剖有些相关误解)
那么具体实现的时候,我们通过魔改他们的DFS序(优先遍历同一条重链上的子节点),然后把新版DFS序塞进线段树
这样重链就都头尾相接了 =w=
这里不对树剖做出详细的讲解(反正前人之述备矣而且还有ACdreamer大大的解释)
只是一些零散的注释
如果明明敲起来很顺又不觉得有什么问题
看看你的函数有没有返回答案= =
(本蒟蒻忘记返回值结果挂了)
关于如何跳链 :
操作的时候优先操作重链链头深度更深的
也就是不停地操作深链然后一步步跳到同一条链上
Code
1 #include<cstdio> 2 #include<iostream> 3 #define maxn 1000000 4 #define lc (rt<<1) 5 #define rc (rt<<1|1) 6 #define mid ((L+R)/2) 7 using namespace std; 8 9 const int inf = 1e9; 10 11 int arr[maxn],siz[maxn],fa[maxn],depth[maxn],son[maxn],top[maxn],tid[maxn],TIM; 12 int back[maxn],n,q; 13 14 struct edge{ 15 int from,v; 16 }e[maxn]; 17 int tot,first[maxn]; 18 void insert(int u,int v){ tot++; e[tot].from = first[u]; e[tot].v = v; first[u] = tot; } 19 20 struct node{ 21 int sum,maxx,lazy; 22 }Tree[maxn]; 23 24 void maintain(int rt){ 25 Tree[rt].sum = Tree[lc].sum+Tree[rc].sum; 26 Tree[rt].maxx = max(Tree[lc].maxx,Tree[rc].maxx); 27 } 28 29 void pushdown(int rt,int L,int R){ 30 if(Tree[rt].lazy == -inf) return; 31 Tree[lc].lazy = Tree[rt].lazy; 32 Tree[rc].lazy = Tree[rt].lazy; 33 Tree[rt].lazy = -inf; 34 Tree[lc].sum = Tree[rt].lazy*(mid-L+1); 35 Tree[lc].maxx = Tree[rt].lazy; 36 Tree[rc].sum = Tree[rt].lazy*(R-mid); 37 Tree[rc].maxx = Tree[rt].lazy; 38 } 39 40 void build(int rt,int L,int R){ 41 Tree[rt].lazy = -inf; 42 if(L == R){ 43 Tree[rt].sum = arr[L]; 44 Tree[rt].maxx = arr[L]; 45 }else{ 46 build(lc,L,mid); 47 build(rc,mid+1,R); 48 49 maintain(rt); 50 } 51 } 52 53 void modify(int rt,int L,int R,int qL,int qR,int val){ 54 pushdown(rt,L,R); 55 if(qL <= L && R <= qR){ 56 Tree[rt].lazy = val; 57 Tree[rt].sum = val*(R-L+1); 58 Tree[rt].maxx = val; 59 }else{ 60 if(qL <= mid) modify(lc,L,mid,qL,qR,val); 61 if(qR > mid) modify(rc,mid+1,R,qL,qR,val); 62 63 maintain(rt); 64 } 65 } 66 67 int max_query(int rt,int L,int R,int qL,int qR){ 68 pushdown(rt,L,R); 69 if(qL <= L && R <= qR) return Tree[rt].maxx; 70 else{ 71 int ans = -inf; 72 if(qL <= mid) ans = max(ans,max_query(lc,L,mid,qL,qR)); 73 if(qR > mid) ans = max(ans,max_query(rc,mid+1,R,qL,qR)); 74 return ans; 75 } 76 } 77 78 int sum_query(int rt,int L,int R,int qL,int qR){ 79 pushdown(rt,L,R); 80 if(qL <= L && R <= qR) return Tree[rt].sum; 81 else{ 82 int ans = 0; 83 if(qL <= mid) ans += sum_query(lc,L,mid,qL,qR); 84 if(qR > mid) ans += sum_query(rc,mid+1,R,qL,qR); 85 return ans; 86 } 87 } 88 89 void dfs(int now){ 90 siz[now] = 1; 91 for(int i = first[now];i;i = e[i].from){ 92 int v = e[i].v; 93 if(v != fa[now]){ 94 fa[v] = now; 95 depth[v] = depth[now]+1; 96 dfs(v); 97 siz[now] += siz[v]; 98 if(!son[now] || siz[v] > siz[son[now]]) 99 son[now] = v; 100 } 101 } 102 } 103 104 void dfs2(int now,int upper){ 105 top[now] = upper; 106 tid[now] = ++TIM; 107 back[TIM] = now; 108 if(!son[now]) return; 109 dfs2(son[now],upper); 110 for(int i = first[now];i;i = e[i].from){ 111 int v = e[i].v; 112 if(v != fa[now] && v != son[now]) 113 dfs2(v,v); 114 } 115 } 116 117 void CHANGE(int u,int val){ 118 modify(1,1,n,tid[u],tid[u],val); 119 } 120 121 int QMAX(int u,int v){ 122 if(depth[top[u]] > depth[top[v]]) swap(u,v); 123 int ans = -inf; 124 while(top[u] != top[v]){ 125 ans = max(max_query(1,1,n,tid[top[v]],tid[v]),ans); 126 v = fa[top[v]]; 127 if(depth[top[u]] > depth[top[v]]) swap(u,v); 128 }if(depth[u] > depth[v]) swap(u,v); 129 ans = max(ans,max_query(1,1,n,tid[u],tid[v])); 130 return ans; 131 } 132 133 int QSUM(int u,int v){ 134 if(depth[top[u]] > depth[top[v]]) swap(u,v); 135 int ans = 0; 136 while(top[u] != top[v]){ 137 ans += sum_query(1,1,n,tid[top[v]],tid[v]); 138 v = fa[top[v]]; 139 if(depth[top[u]] > depth[top[v]]) swap(u,v); 140 }if(depth[u] > depth[v]) swap(u,v); 141 ans += sum_query(1,1,n,tid[u],tid[v]); 142 return ans; 143 } 144 145 int main(){ 146 scanf("%d",&n); 147 for(int i = 1;i < n;i++){ 148 int x,y; scanf("%d%d",&x,&y); 149 insert(x,y); insert(y,x); 150 }depth[1] = 1; dfs(1); dfs2(1,1); 151 152 for(int i = 1;i <= n;i++) 153 scanf("%d",&arr[tid[i]]); 154 build(1,1,n); 155 156 scanf("%d",&q); 157 while(q--){ 158 char str[10]; 159 scanf("%s",str); int a,b; 160 switch(str[1]){ 161 case 'M': //QMAX 162 scanf("%d%d",&a,&b); 163 printf("%d\n",QMAX(a,b)); 164 break; 165 case 'S': //QSUM 166 scanf("%d%d",&a,&b); 167 printf("%d\n",QSUM(a,b)); 168 break; 169 case 'H': //CHANGE 170 scanf("%d%d",&a,&b); 171 CHANGE(a,b); 172 break; 173 } 174 } 175 176 return 0; 177 }