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("");
}
}
/*
*/