题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036
解:树链剖分基础题
对于线性表,我们可以通过线段树、树状数组等数据结构成段修改成段查询,如果想要在树上成段修改查询,我们就需要进行树剖
树剖的大体思路是把树拆成链然后以一定次序放在线性表上,然后利用各种数据结构处理线性表
比如处理树上两点u、v之间的路径,我们要知道这条路径与之前拆分的哪些链相交,然后查询线性表上相交部分
那么时间复杂度为=路径与拆分链相交数*数据结构处理每条链时间
可以有各种拆分链方法,目前最好的一种是轻重链拆分,拆分后保证任意路径穿过拆分链数为log(n)
树剖学习推荐博客:http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html
习题推荐:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#overview
1 /* 2 * Problem: 3 * Author: SHJWUDP 4 * Created Time: 2015/6/10 星期三 23:13:56 5 * File Name: 233.cpp 6 * State: 7 * Memo: 8 */ 9 #include <iostream> 10 #include <cstdio> 11 #include <cstring> 12 #include <algorithm> 13 14 using namespace std; 15 16 const int MaxA=3e4+7; 17 18 struct Edge { 19 int v, nt; 20 Edge(){} 21 Edge(int v, int nt):v(v), nt(nt){} 22 } edges[MaxA<<1]; 23 24 int head[MaxA], edgeNum; 25 26 struct SegmentTree { 27 int n; 28 int c[MaxA<<2][2]; ///0:sum 1:max 29 int *val; 30 int p, v; 31 int L, R, op; 32 #define lson l, m, rt<<1 33 #define rson m+1, r, rt<<1|1 34 35 void pushUp(int rt) { 36 c[rt][0]=c[rt<<1][0]+c[rt<<1|1][0]; 37 c[rt][1]=max(c[rt<<1][1], c[rt<<1|1][1]); 38 } 39 40 void doBuild(int l, int r, int rt) { 41 if(l==r) { 42 c[rt][0]=c[rt][1]=val[l]; 43 } else { 44 int m=(l+r)>>1; 45 doBuild(lson); 46 doBuild(rson); 47 pushUp(rt); 48 } 49 } 50 51 void build(int n, int* val) { 52 this->n=n; this->val=val; 53 doBuild(1, n, 1); 54 } 55 56 void doUpdate(int l, int r, int rt) { 57 if(l==r) { 58 c[rt][0]=c[rt][1]=v; 59 } else { 60 int m=(l+r)>>1; 61 if(p<=m) doUpdate(lson); 62 else doUpdate(rson); 63 pushUp(rt); 64 } 65 } 66 67 void update(int p, int v) { 68 this->p=p; this->v=v; 69 doUpdate(1, n, 1); 70 } 71 72 int doQuery(int l, int r, int rt) { 73 if(L<=l && r<=R) { 74 return c[rt][op]; 75 } else { 76 int m=(l+r)>>1; 77 int res=(op==0?0:0x80000000); 78 if(L<=m) res=(op==0?res+doQuery(lson):max(res, doQuery(lson))); 79 if(m<R) res=(op==0?res+doQuery(rson):max(res, doQuery(rson))); 80 return res; 81 } 82 } 83 84 int query(int L, int R, int op) { 85 this->L=L; this->R=R; this->op=op; 86 return doQuery(1, n, 1); 87 } 88 #undef lson 89 #undef rson 90 } st; 91 92 int N; 93 int oval[MaxA], val[MaxA]; ///oval:树结点编号对应的值 94 ///val:线性表编号对应的值 95 void init() { 96 edgeNum=0; 97 memset(head, -1, sizeof(head)); 98 } 99 void addEdge(int u, int v) { 100 edges[edgeNum]=Edge(v, head[u]); 101 head[u]=edgeNum++; 102 } 103 namespace LCT { 104 int fa[MaxA]; ///fa[x]:x的父亲结点 105 int siz[MaxA]; ///siz[x]:x子树的结点数 106 int son[MaxA]; ///son[x]:x的重儿子,即siz最大的儿子(有平行的无所谓,随便一个即可 107 int dep[MaxA]; ///dep[x]:x的结点深度 108 int top[MaxA]; ///top[x]:x所在重链中dep值最小的结点 109 ///重边:结点与重儿子的连边 110 ///重链:由重边连成的路径 111 int w[MaxA]; ///w[x]:x在线性表中的编号 112 int id; ///id:生成w数组时用的计数变量 113 114 int dfs1(int u, int d) { 115 siz[u]=1; dep[u]=d; son[u]=-1; 116 for(int i=head[u]; ~i; i=edges[i].nt) { 117 Edge& e=edges[i]; 118 if(e.v==fa[u]) continue; 119 fa[e.v]=u; 120 siz[u]+=dfs1(e.v, d+1); 121 if(son[u]==-1 || siz[son[u]]<siz[e.v]) son[u]=e.v; 122 } 123 return siz[u]; 124 } 125 126 void dfs2(int u, int tp) { 127 w[u]=++id; top[u]=tp; 128 if(son[u]!=-1) dfs2(son[u], tp); 129 for(int i=head[u]; ~i; i=edges[i].nt) { 130 Edge& e=edges[i]; 131 if(e.v==fa[u] || e.v==son[u]) continue; 132 dfs2(e.v, e.v); 133 } 134 } 135 136 int query(int u, int v, int op) { 137 int res=(op==0?0:0x80000000); 138 int f1=top[u], f2=top[v]; 139 while(f1!=f2) { 140 if(dep[f1]<dep[f2]) { swap(f1, f2); swap(u, v); } 141 res=(op==0?res+st.query(w[f1], w[u], op):max(res, st.query(w[f1], w[u], op))); 142 u=fa[f1]; f1=top[u]; 143 } 144 if(dep[u]>dep[v]) swap(u, v); 145 res=(op==0?res+st.query(w[u], w[v], op):max(res, st.query(w[u], w[v], op))); 146 return res; 147 } 148 149 void update(int p, int v) { 150 st.update(w[p], v); 151 } 152 153 void init() { 154 int root=1; ///随便指定树根 155 id=0; 156 fa[root]=-1; 157 dfs1(root, 0); 158 dfs2(root, root); 159 for(int i=1; i<=N; i++) { 160 val[w[i]]=oval[i]; 161 } 162 st.build(N, val); 163 } 164 } 165 int main() { 166 #ifndef ONLINE_JUDGE 167 freopen("in", "r", stdin); 168 //freopen("out", "w", stdout); 169 #endif 170 while(~scanf("%d", &N)) { 171 init(); 172 for(int i=1; i<N; i++) { 173 int a, b; 174 scanf("%d%d", &a, &b); 175 addEdge(a, b); 176 addEdge(b, a); 177 } 178 for(int i=1; i<=N; i++) { 179 scanf("%d", &oval[i]); 180 } 181 LCT::init(); 182 int Q; 183 scanf("%d", &Q); 184 while(Q--) { 185 char op[7]; 186 int a, b; 187 scanf("%s%d%d", op, &a, &b); 188 if(op[0]=='C') { 189 LCT::update(a, b); 190 } else { 191 if(op[1]=='S') { 192 printf("%d\n", LCT::query(a, b, 0)); 193 } else printf("%d\n", LCT::query(a, b, 1)); 194 } 195 } 196 } 197 return 0; 198 }