http://blog.sina.com.cn/s/blog_7a1746820100wp67.html 别人转的讲解, 看的这个学的。
感觉不是必要的方法, 其他方法也能做的, 一般要维护树种路径的最值时才需要这个算法
spoj375
对边权的路径剖分
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; const int maxn=10000+123; int T[maxn<<2]; int M; void initT(int x) { memset (T, 0, sizeof(T)); M=1<<((int)ceil(log(x+1.0)/log(2.0))); } void update(int x, int v) { for (T[x+=M]=v, x>>=1; x; x>>=1) { T[x]=max(T[x<<1], T[x<<1|1]); } } int query(int l, int r) { int res=-1; for (l+=M-1, r+=M+1; l^r^1; l>>=1, r>>=1) { if(~l&1)res=max(T[l^1], res); if( r&1)res=max(T[r^1], res); } return res; } struct Edge { int v, next, w; }edge[maxn<<1]; int head[maxn], cnt; void addedge(int u, int v, int w) { edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; } int dep[maxn], pos[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn]; int idx; /// pos the position of father edge int seg-tree void dfs(int u) { siz[u]=1; son[u]=-1; for (int p=head[u]; ~p; p=edge[p].next) { const int &v=edge[p].v; if(v==fa[u])continue; fa[v]=u; dep[v]=dep[u]+1; dfs(v); if(siz[v]>siz[son[u]])son[u]=v; siz[u]+=siz[v]; } } void dfs_(int u, int tp) { pos[u]=++idx; top[u]=tp; if(~son[u])dfs_(son[u], top[u]);///非叶节点遍历重儿子 for (int p=head[u]; ~p; p=edge[p].next) { if(edge[p].v!=son[u] && edge[p].v!=fa[u]) dfs_(edge[p].v, edge[p].v);///轻边 } } int find(int u, int v) { int fu=top[u], fv=top[v], tmp=-1; while (fu!=fv) { if(dep[fu]<dep[fv]) { swap(fu, fv); swap(u, v); } tmp=max(tmp, query(pos[fu], pos[u])); u=fa[fu]; fu=top[u]; } if(u==v)return tmp; if(dep[u]>dep[v])swap(u, v);///u v不同,但在同一重链上 return max(tmp, query(pos[son[u]], pos[v])); } void init() { memset (head, -1, sizeof(head)); cnt=0; } int main() { int cas; scanf("%d", &cas); while (cas--) { int n; scanf("%d", &n); init(); idx=dep[1]=0; fa[1]=-1; for (int i=1; i<n; ++i) { int a, b, c; scanf("%d%d%d", &a, &b, &c); addedge(a, b, c); addedge(b, a, c); } dfs(1); dfs_(1, 1); initT(idx); ///printf("idx===%d %d\n", idx, M); for (int u=1; u<=n; ++u) { for (int p=head[u]; ~p; p=edge[p].next) { const int v=edge[p].v; if(dep[v]>dep[u]) update(pos[v], edge[p].w); } } char op[20]; for (scanf("%s", &op); op[0]!='D'; scanf("%s", &op)) { int a, b; scanf("%d%d", &a, &b); if(op[0]=='Q')printf("%d\n", find(a, b)); else { a--; int v1=edge[a<<1].v, v2=edge[a<<1|1].v; if(dep[v1]<dep[v2])v1=v2; update(pos[v1], b); } } } return 0; } /* 2 3 1 2 100 2 3 200 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE 4 1 2 1 2 4 2 3 4 3 QUERY 1 3 Q 1 2 CHANGE 1 3 QUERY 3 4 C 1 3 Q 1 2 DONE */
bupt 649 Gao on a Tree II
对点权的路径剖分
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> #include <map> using namespace std; const int maxn=200000+123; //int T[maxn<<2]; ///map<int, int>mp[maxn<<2]; multimap<int, int>mm; struct Edge { int v, next, w; }edge[maxn<<1]; int head[maxn], cnt; void addedge(int u, int v, int w=0) { edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; } int dep[maxn], pos[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn]; int idx; /// pos the position of father edge int seg-tree ///树链剖分就是将树拆成链, void dfs(int u) { siz[u]=1; son[u]=-1; for (int p=head[u]; ~p; p=edge[p].next) { const int &v=edge[p].v; if(v==fa[u])continue; fa[v]=u; dep[v]=dep[u]+1; dfs(v); if(siz[v]>siz[son[u]])son[u]=v; siz[u]+=siz[v]; } } void dfs_(int u, int tp) { pos[u]=++idx; top[u]=tp; if(~son[u])dfs_(son[u], top[u]);///非叶节点遍历重儿子 for (int p=head[u]; ~p; p=edge[p].next) { if(edge[p].v!=son[u] && edge[p].v!=fa[u]) dfs_(edge[p].v, edge[p].v);///轻边 } } bool find(int u, int v, int x) { int fu=top[u], fv=top[v]; multimap<int, int>::iterator itu=mm.upper_bound(x), it; multimap<int, int>::iterator itl=mm.lower_bound(x); int l, r; if(itl==mm.end() || itl->first!=x) return false; while (fu!=fv) { if(dep[fu]<dep[fv]) { swap(fu, fv); swap(u, v); } ///tmp=max(tmp, query(pos[fu], pos[u])); //if(query(pos[fu], pos[u]))return true; ///if(pos[fu]<=l && pos[u]) ///printf("%d %d\n", pos[fu], pos[u]); for (it=itl; it!=itu; ++it) if(pos[fu]<=it->second && pos[u]>=it->second)return true; u=fa[fu]; fu=top[u]; ///printf("f%d f%d\n", fu, fv); } if(u==v) { for (it=itl; it!=itu; ++it) if(pos[u]==it->second)return true; } if(dep[u]>dep[v])swap(u, v);///u v不同,但在同一重链上 ///return max(tmp, query(pos[son[u]], pos[v])); ///printf("p %d p %d\n", pos[u], pos[v]); for (it=itl; it!=itu; ++it) if(pos[u]<=it->second && pos[v]>=it->second)return true; return false; } void init() { memset (head, -1, sizeof(head)); cnt=0; } void initr(int rt) { idx=0; dep[rt]=0; fa[rt]=0; } int w[maxn]; int main() { int cas; scanf("%d", &cas); while (cas--) { int n, m; scanf("%d%d", &n, &m); init(); initr(1); for (int i=1; i<=n; ++i) { scanf("%d", w+i); } for (int i=1; i<n; ++i) { int a, b; scanf("%d%d", &a, &b); addedge(a, b); addedge(b, a); } dfs(1); dfs_(1, 1); ///initT(idx); mm.clear(); for (int i=1; i<=n; ++i) ///update(pos[i], w[i]); mm.insert(make_pair(w[i], pos[i])); ///for (int i=0; i<=n; ++i)printf("%d %d\n", i, pos[i]); for (int i=0; i<m; ++i) { char op[5]; scanf("%s", op); if(op[0]=='Q') { int a, b, c; scanf("%d%d%d", &a, &b, &c); if(find(a, b, c))puts("Find"); else puts("NotFind"); } else { int a, b; scanf("%d%d", &a, &b); multimap<int, int>::iterator itu=mm.upper_bound(w[a]), it; multimap<int, int>::iterator itl=mm.lower_bound(w[a]); for (it=itl; it!=itu; ++it) { if(it->second==pos[a]) { mm.erase(it); break; } } mm.insert(make_pair(b, pos[a])); w[a]=b; } } puts(""); } } /* */