之前就學過樹鏈剖分的原理,只會樹鏈剖分LCA,今天做了一道“樹鏈剖分+數據結構”的題,雖然很簡單,但可以當模板用一用,粘到這裏。
樹鏈剖分簡單描述(可能不大對):
- 第一步就是劃分輕重邊,按每一棵子樹的大小,與形成子樹最大的一個子節點是重邊,其餘爲輕邊,然後就得到了輕重鏈。
- 之後就可以用數據結構維護一些東西了,可以是點也可以是邊。
- 對節點 x 到 y 間的路徑進行操作時,分別找到 x 和 y 所在鏈(無論輕重)的頂,若相同,直接往上跳並維護操作,若不同,讓鏈頂深度大的向上跳到它的父節點,找到一條新鏈,繼續上述操作(感覺跟樹鏈剖分LCA差不多,最終他們會跳到同一個點)。
模板題:SPOJ 375
題目大意:給出一棵樹,每條邊編號 1~n-1 有權值,可修改第i條邊的權值,支持詢問從節點 x 到節點 y 的路徑上的最大邊權。
code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 10010
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define Mid(x,y) ((x+y)>>1)
using namespace std;
struct edge{
int from,to,ne;
}e[N<<1];
int head[N],tot=0;
void push(int x,int y)
{
e[++tot].from=x; e[tot].to=y; e[tot].ne=head[x]; head[x]=tot;
e[++tot].from=y; e[tot].to=x; e[tot].ne=head[y]; head[y]=tot;
}
int fa[N],siz[N],son[N],w[N],p[N],deep[N],tree_id;
int fp[N];
struct node{
int l,r,mx;
}tree[N<<2];
void build(int l,int r,int now) //線段樹維護最大邊權
{
tree[now].l=l; tree[now].r=r;
tree[now].mx=0;
if (l==r) return;
int mid=Mid(l,r);
build(l,mid,L(now));
build(mid+1,r,R(now));
}
void update(int pos,int val,int now)
{
if (tree[now].l==tree[now].r)
{
tree[now].mx=val;
return;
}
int mid=Mid(tree[now].l,tree[now].r);
if (pos<=mid) update(pos,val,L(now));
else update(pos,val,R(now));
tree[now].mx=max(tree[L(now)].mx,tree[R(now)].mx);
}
int query(int l,int r,int now)
{
if (l==tree[now].l&&r==tree[now].r)
return tree[now].mx;
int mid=Mid(tree[now].l,tree[now].r);
if (r<=mid) return query(l,r,L(now));
else if (l>mid) return query(l,r,R(now));
else return max(query(l,r,L(now)),query(l,r,R(now)));
}
int find(int x,int y) //往上跳
{
int f1=p[x],f2=p[y];
int tmp=0;
while (f1!=f2)
{
if (dep[f1]<dep[f2])
swap(f1,f2),swap(x,y);
tmp=max(tmp,query(w[f1],w[x],1));
x=fa[f1],f1=p[x];
}
if (x==y) return tmp;
if (dep[x]>dep[y]) swap(x,y);
return max(tmp,query(w[son[x]],w[y],1));
}
void dfs(int now,int pre,int dep) //輕重邊
{
son[now]=0,fa[now]=pre,siz[now]=1,deep[now]=dep;
for (int i=head[now];i;i=e[i].ne)
{
int v=e[i].to;
if (v==fa) continue;
dfs(v,now,dep+1);
siz[now]+=siz[v];
if (siz[v]>siz[son[now]]) son[now]=v;
}
}
void dfs2(int now,int pre) //輕重鏈
{
w[now]=++tree_id; /* now節點在線段樹上的位置 */
p[now]=pre; /* now所在鏈的鏈頂 */
if (son[now])
dfs2(son[now],pre);
else return;
for (int i=head[now];i;i=e[i].ne)
{
int v=e[i].to;
if (v!=fa&&v!=son[now]) dfs2(v,v);
}
}
int n,D[N][3];
void init()
{
memset(head,0,sizeof(head)); tot=0;
memeset(son,0,sizeof(son));
tree_id=0;
}
int main()
{
int T;
scanf("%d",&T);
char s[10];
while (T--)
{
scanf("%d",&n);
init();
for (int i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
D[i][0]=x,D[i][1]=y,D[i][2]=z;
}
dfs(1,1,0);
dfs2(1,1);
build(1,n,1);
for (int i=1;i<n;i++)
{
if (dep[D[i][0]]>dep[D[i][1]]) swap(D[i][1],D[i][0]);
update(w[D[i][1]],D[i][2],1);
}
while (scanf("%s",s))
{
if (s[0]=='D') break;
int x,y;
scanf("%d%d",&x,&y);
if (s[0]=='C') update(w[D[x][1]],y,1);
else printf("%d\n",find(x,y));
}
}
}